2011-07-13 61 views
0

背景/平台:TcpClient的持续发送了一段时间,即使没有连接

.NET 4/C#

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

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

情景/问题

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

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

下面是发送(使用NetworkStream.Write)的代码:发送另一个45-50秒,不断去,最后它打破

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

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

。 这些是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不应该立即失败?

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

回答

1

你不能。如果你之间有交换机/路由器,你会如何检测到这一点?您的电脑仍然完全连接。

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

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

在调用Write方法后,底层套接字返回实际发送到主机的字节数。 SendTimeout属性决定了TcpClient在收到返回的字节数之前等待的时间。如果超时在Send方法成功完成之前超时,则TcpClient将引发一个SocketException。默认情况下没有超时。

+0

所以基本上,知道连接是否仍然有效的唯一方法是服务器(本例中的设备)每XY秒发送一次自定义协议消息,然后如果我没有收到它一个XY(或多一点)秒我知道出了什么问题?我知道,当连接失败时,Read操作将返回0(因为接收到0字节),但它似乎只能在Read上工作,而不能在Write上工作。 –

+0

不是。数据包仍然可以在这里和这里之间缓冲。唯一可以衡量的是rtt(往返时间)。如果你真的想要构建你正在描述的东西,那么切换到不执行重发的udp(等等)。 – sisve