我有一个数据收集系统,通过TCP连接将数据从收集计算机(服务器)传递到绘图计算机(客户端) . 第一次运行集合时,代码工作正常 . 如果系统闲置超过三分钟,代码将继续在后续运行中正常工作 . 如果系统保持空闲状态超过三分钟,则传输将在前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秒 . 在此期间,客户端永远不会看到DataAvailable在12秒过后才会成功 . 发送超时保留为默认值,因此它应该是无限的 . 12秒的时间似乎与发送的数据量有些关系 .
我在这个系统中做了一些不同的事情,而不是在客户端应用程序启动时创建TcpClient,当客户端需要连接时,我新建了一个TcpClient . On Disconnect我处理通过TcpCLient.GetStream检索的Stream,然后关闭TcpClient .
我只是希望能够深入了解为什么闲置三分钟会产生这种影响(两个系统都在运行XP) .
EDIT - Problem Solved but understanding is proving elusive
在服务器上,我使用了一个单独的线程,该线程使用TcpListener.AcceptTcpClient()来允许客户端连接 . AcceptTcpClient()返回一个TcpClient对象 . 我会定期检查TcpClient的IsConnected属性,以便我知道客户端是否断开连接(即测量结束),然后我将再次挂起AcceptTcpClient()并等待下一次测量的开始 . 问题是即使客户端的TcpClient断开连接,服务器的TcpClient.IsConnected也总是返回true .
我通过让客户端向服务器发送消息(而不是通过TCP)来解决问题,然后服务器强制断开连接 . 现在一切正常但我确信我没有正确使用这个API . 虽然我可以看到异步接受的方法,但我看不到服务器在客户端断开连接时应该如何找出,我不明白为什么服务器的TcpClient.IsConnected属性在不再存在时返回true有效连接 .
另外我很晚才注意到ExclusiveAddressUse属性,所以我从来没有将它设置为true . 系统的行为就像是在几分钟内 Build 了另一个客户端连接,重复使用了相同的连接,服务器可以将数据发送到客户端(即,就好像客户端从未断开连接一样) . 如果断开连接超过三分钟,则接受新的客户端连接(尽管我可以告诉我的代码永远不会返回到AcceptTcpClient()行),但它不再是服务器连接的相同连接发送 .
2 回答
处理IO时
Thread.Sleep
是EVIL . 请改用socket.BeginReceive
,如果仍然无效,请返回 .虽然我仍然不明白为什么我的客户端可以在我的服务器未在AcceptTcpClient上挂起时连接,但我认为我确实理解为什么即使客户端断开连接,Connected也会返回true . 我在MSDN上挖掘了底层的Socket文档并看到了这个:
由于客户端知道退出是因为服务器停止发送数据,因此在客户端退出之前的最后一次发送是成功的 . 我认为Connected是这个属性的 terrible 名称 . 它应该是WasConnected或WasConnectedAtLastSend,虽然它更加冗长会让我心痛不已(因此很快就会阅读MSDN文档) .