【发布时间】:2011-10-01 02:15:37
【问题描述】:
我有一个数据收集系统,它通过 TCP 连接将数据从收集计算机(服务器)传递到绘图计算机(客户端)。该代码在第一次运行集合时运行良好。如果系统空闲时间不超过三分钟,则代码在后续运行中继续正常工作。如果系统保持空闲超过 3 分钟,则传输会在前 12 秒左右挂起(长到足以导致收集缓冲区溢出)。
在每次收集开始时,客户端会进入 30 秒的循环,每 1 毫秒检查一次是否 _clientStream.DataAvailable = true。该循环看起来与此类似(删除了一些错误检查代码):
public bool WaitForData(int maxWaitInMs)
{
DateTime start_time = DateTime.Now;
while (!_clientStream.DataAvailable )
{
Thread.Sleep(DATA_WAIT_DELAY); //1 ms
TimeSpan elapsed_time = DateTime.Now - start_time;
if (elapsed_time.TotalMilliseconds > maxWaitInMs)
{
return false;
}
}
return true;
}
服务端只是在做固定长度数据的简单写入
_dataTcpServer.SendData(packet_buffer, OFFSET, packet.Size());
当问题发生时,我可以从调试器中得知服务器调用了一次 SendData,返回获取下一个数据包再次调用 send 方法,然后在 SendData 调用上挂断大约 12 秒。与此同时,在 12 秒过去之前,客户端永远不会看到 DataAvailable 变为 true。发送超时保留为默认值,因此它应该是无限的。 12 秒的时间似乎确实与发送的数据量有关。
我在这个系统中做了不同的事情,不是在客户端应用程序启动时创建 TcpClient,而是在客户端需要连接时新建一个 TcpClient。在断开连接时,我处理通过 TcpCLient.GetStream 检索到的流并关闭 TcpClient。
我只是希望了解为什么闲置三分钟会产生这种影响(两个系统都运行 XP)。
编辑 - 问题已解决,但难以理解
在服务器上,我使用了一个单独的线程,该线程使用 TcpListener.AcceptTcpClient() 来允许客户端连接。 AcceptTcpClient() 返回一个 TcpClient 对象。我会定期检查 TcpClient 的 IsConnected 属性,以便知道客户端是否断开连接(即测量结束),然后我会再次挂起 AcceptTcpClient() 并等待下一次测量的开始。问题是即使客户端的 TcpClient 断开连接,服务器的 TcpClient.IsConnected 总是返回 true。
我通过让客户端向服务器发送消息(不是通过 TCP)然后服务器强制断开连接来解决问题。现在一切正常,但我确信我没有正确使用这个 API。虽然我可以看到异步接受的方法,但我看不到服务器应该如何找出客户端断开连接的时间,也看不到为什么服务器的 TcpClient.IsConnected 属性在不再存在时会返回 true有效的连接。
此外,我注意到 ExclusiveAddressUse 属性也很晚,所以我从未将其设置为 true。系统的行为就像在几分钟内建立了另一个客户端连接,重复使用相同的连接并且服务器可以向客户端发送数据(即,就好像客户端从未断开连接一样)。如果断开连接后超过三分钟,则接受新的客户端连接(尽管据我所知,我的代码从未回到 AcceptTcpClient() 行),但它不再是与服务器相同的连接继续发送。
【问题讨论】: