【问题标题】:TcpClient keeps sending for a while even though there is no connection即使没有连接,TcpClient 也会持续发送一段时间
【发布时间】:2014-02-10 07:03:52
【问题描述】:

背景/平台:

.NET 4 / C#

我有一个通过以太网连接到嵌入式设备的 C#TcpClient。 我正在使用两个计时器 - 一个用于将接收到的数据存储到本地 Queue<MyMessage> 中,另一个用于通过 TCP 将数据从另一个 Queue<MyMessage> 发送到嵌入式设备。这两个都运行每个200 ms 并发送/读取他们必须发送/读取的任何内容。

还有另一个计时器发送一个保持活动的数据包every second(目前仅用于调试目的)。

场景/问题

建立连接后,嵌入式设备开始向我的TcpClient发送一些数据。这按预期工作(请参阅下面的消息日志)。但是,然后我关闭设备(所以它根本不起作用)。这意味着它甚至无法正确关闭 TCP。但没关系。我想测试如果在真实情况下发生这样的事情会发生什么。

但是,即使服务器(设备)不再在线,TcpClient 仍然会继续发送数据。

这里是发送代码(使用NetworkStream.Write):

while (messagesToSend.Count > 0)
{
    MyMessage msg = messagesToSend.Dequeue();
    clientStream.Write(msg.Data, 0, msg.Data.Length);

    Debug.WriteLine(DateTime.Now.ToString() + " Sent: " + msg.MessageID);
}

发送继续持续 45-50 秒,然后最终中断。 这些是为 TcpClient 和 NetworkStream 设置的选项

client.LingerState = new LingerOption(true, 0);
client.NoDelay = true;
client.SendTimeout = 3000;
clientStream.WriteTimeout = 3000;

这是调试输出:

16:32:02 Connecting
16:32:02 Authorizing
16:32:02 Sent: 255
16:32:02 Sent: 0
16:32:02 Authorized
16:32:02 Connected
16:32:02 Received: 255
16:32:02 Received: 226
...
... some regular communication here
...
16:32:06 Received: 251
16:32:06 Sent: 0
16:32:07 Received: 251
16:32:07 Sent: 0            // At this point I have turned off the device
16:32:08 Sent: 0
16:32:09 Sent: 0
...
... every second the same message
...
16:32:54 Sent: 0
16:32:55 Sent: 0
16:32:56 Sent: 0
16:32:57 Unable to write data to the transport connection: An established connection was aborted by the software in your host machine.
16:32:57 CommunicationError

为什么连接需要很长时间才能意识到它已关闭?如果主机没有响应,NetworkStream.Write 不应该立即失败吗?

如何检测设备的电源被切断,连接不再有效?

【问题讨论】:

    标签: c# connection send tcpclient


    【解决方案1】:

    你不能。如果您之间有交换机/路由器,您将如何检测到这一点?您的计算机仍处于完全连接状态。

    TCP/IP 以这种方式工作。接收方未确认的任何数据包都会重新发送几次(通常超时时间会增加)。超时值和重发次数是特定于您的 tcp 堆栈/操作系统的实现。

    TcpClient.SendTimeout 属性仅控制将数据进一步发送到流中所需的时间。

    调用 Write 方法后,底层 Socket 返回实际发送到主机的字节数。 SendTimeout 属性确定 TcpClient 在接收返回的字节数之前将等待的时间量。如果超时在 Send 方法成功完成之前到期,则 TcpClient 将抛出 SocketException。默认没有超时。

    【讨论】:

    • 所以基本上,知道连接是否仍然有效的唯一方法是服务器(在我的情况下是设备)每 XY 秒向我发送一些自定义协议消息,然后如果我没有接收 XY(或多一点)秒我知道出了什么问题?我知道当连接失败时读取操作将返回 0(因为已收到 0 个字节),但它似乎只适用于读取,而不适用于写入。
    • 并非如此。数据包仍然可以在那里和这里之间的某个地方缓冲。您唯一可以测量的是 rtt(往返时间)。如果您确实想构建您所描述的内容,请切换到不实现重新发送(除其他外)的 udp。
    猜你喜欢
    • 2017-05-21
    • 1970-01-01
    • 2021-12-07
    • 2020-12-10
    • 2011-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多