除非在关闭NetworkStream之前使用Thread.Sleep(),否则NetworkStream并不总是发送数据。我究竟做错了什么?

时间:2012-10-19 08:09:43

标签: c# tcpclient

我在向同一台计算机上运行的另一台TcpClient发送一小段数据(日期)时遇到问题。

在下面的代码中,您将看到它在关闭NetworkStream之前休眠。如果我删除Sleep,则会导致间歇性问题,而数据不会在另一端出现。

我在这里做错了吗?

using (TcpClient client = new TcpClient())
{
    client.Connect(new IPEndPoint(IPAddress.Loopback, _tcpServerPort));
    NetworkStream clientStream = client.GetStream();

    byte[] buffer = new ASCIIEncoding().GetBytes(theDateObject.ToString("yyyy-MM-dd HH:mm:ss"));                            
    clientStream.Write(buffer, 0, buffer.Length);
    clientStream.Flush();
    System.Threading.Thread.Sleep(1000); // Remove this line and the data may not arrive at the other end
    clientStream.Close();
}

其他一些信息:

  • 在某些计算机上,您可以删除Sleep而不会导致问题(可能是较慢的计算机?)
  • 我尝试用Close(int timeout)关闭NetworkStream(而不是睡觉),但这没有帮助。
  • 1000毫秒的值是任意的 - 我怀疑其他值也会起作用。问题是:为什么首先需要它?

2 个答案:

答案 0 :(得分:1)

在NetworkStream上以超时方式调用close意味着网络流将在后台保持打开X时间以允许发送剩余数据。在后台非常重要,因为您的代码未被此阻止。因为您将tcpClient封装在using语句中,所以客户端和NetworkStream内部将在您关闭调用后直接处理。在这种情况下睡眠是有效的,因为它允许发送数据并在此期间阻止您的方法,以防止它强行处理其资源。

更干净的解决方案是在TcpClient上设置一个具有足够长超时的活动LingerState。请参阅:http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.lingerstate.aspx

答案 1 :(得分:0)

如果您的接收队列不为空(您从尚未读取的服务器获取接收缓冲区中的数据,则配置Socket(客户端)发送TCP RST(重置连接))和发送中的数据丢弃缓冲区,即如果尚未丢失,则等待发送缓冲区为空,然后终止tcp连接。

一种解决方法是关闭发送渠道:

    client.Client.Shutdown(SocketShutdown.Send)
    clientStream.Close();
}
在关闭客户端(而不是thread.sleep)之前

,在这种情况下,连接不会被重置。

.Flush()也不对网络流做任何事情。

请参阅:http://cs.baylor.edu/~donahoo/practical/JavaSockets/RecvQClose.pdf