【问题标题】:Why does my connection drop when the client doesn't send any more data?当客户端不再发送任何数据时,为什么我的连接断开?
【发布时间】:2021-11-13 19:05:25
【问题描述】:

所以我有一个服务器,它接受传入的连接,然后抓取TcpClient 以获取流,以便可以通过该流发送和接收数据。

至于现在我只是想读取数据,而且效果很好!唯一的问题是,如果我将数据作为客户端发送到服务器,然后服务器会按应有的方式解释数据,它会按照预期的方式读取每一位。但是如果数据包在接下来的 50 - 60 秒内不再发送数据,服务器就会抛出这个异常

无法从传输连接读取数据:现有连接被远程主机强行关闭..

一旦客户端连接,服务器就会进入循环并开始读取数据

while (isConnected)
{
    var packetOpCode = nr.ReadByte();
    var packetSize = Constants.INCOMING_SIZES[packetOpCode];
    NetPacket packet;

        /* i.e 127 */
        packetSize = nr.ReadByte();
        var payload = nr.ReadBytes(packetSize);
        packet = new NetPacket
        {
            OpCode = packetOpCode,
            Length = packetSize,
            Payload = payload
        };
    
    _packets.Add(packet);
    /* If anything here crashes, then treat it as a faulty packet and disconnect the user. */
    Console.WriteLine(
        $"#: {_id} Queue: [{_packets.Count}] - Packet with ID: {packet.OpCode} added. ");
    File.AppendAllText("Log.txt",
        $"#: {_id} Queue: [{_packets.Count}] - Packet with ID: {packet.OpCode} added. \n");
}

其中nr 是我的NetReader 类的一个实例

public class NetReader : BinaryReader
{
    private readonly NetworkStream _ns;
    public NetReader(NetworkStream ns) : base(ns)
    {
        _ns = ns;
        base.BaseStream.ReadTimeout = System.Threading.Timeout.Infinite;
    }
}

我在客户端上所做的只是

  • 连接到服务器
  • 创建一个 byte[] 并通过 Client.Send(..); 通过该连接发送它

所以它只发送一个数据包,然后它处于空闲状态,应用程序不会退出或其他任何事情,它只是不再发送数据。

client.Connect("127.0.0.1", portNumber);
PacketBuilder builder = new PacketBuilder();
builder.AddOpCode(4);
builder.AddByte(4);
builder.AddString("Test");
var packet = builder.GetByteArray();
client.Client.Send(packet, packet.Length, SocketFlags.None);

数据包看起来像这样4 4 54 65 73 74

由于服务器正在循环,一旦读取第一个数据包就尝试读取更多数据,第二次迭代它将卡在这一行var packetOpCode = nr.ReadByte();,因为它是一个阻塞调用。

好像某处有超时,但我不知道是什么导致连接断开。

为什么我在服务器上收到异常?某处是否存在隐藏超时?

【问题讨论】:

  • 我不是 C#-er,但我想 TcpClient 有办法设置 TCP 保持活动并调整其参数。
  • 看起来TcpClient.Client 返回具有SetSocketOption 方法的底层套接字,您可以使用该方法配置TCP keep-alives.
  • TcpClientSendTimeoutReceiveTimeout 可以设置。如果我没记错的话,默认超时是 1 分钟。
  • @Rafael 可能,我觉得这可能与 tcp 的工作方式以及假设如何存在 ACK 等有关,我在 TCP 方面还没有受过良好的教育,所以我可能是错的。
  • @WBuck 如果你能找到任何关于默认超时的文档,那就太棒了!

标签: c# sockets tcp tcpclient


【解决方案1】:

TCP 不会超时,除非它的实现专门实现了超时。

100 年不发送任何数据的已建立 TCP 连接仍然是已建立的 TCP 连接。

只要每一端仍然存在,任何一端都没有理由向另一端发送数据包,它们都可以永远坐在那里等待。

所以:

  1. 服务器和/或客户端可以关闭空闲连接以释放资源。

  2. 防火墙和 NAT 设备可以清除状态信息,这样当您再次使用时,您的连接将不再有效。

  3. 防火墙和 NAT 设备也可以通过向客户端或服务器发送 RST 来假关闭空闲的 tcp 连接。

根据您的解释,听起来服务器正在关闭连接,因为它没有看到任何数据,因此它正在释放资源。

检查您的服务器实现。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-07-24
    • 1970-01-01
    • 2015-05-30
    • 1970-01-01
    • 2019-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多