简体   繁体   中英

NetworkStream doesn't always send data unless I Thread.Sleep() before closing the NetworkStream. What am I doing wrong?

I'm having problems sending a very small piece of data (a date) to another TcpClient running on the same computer.

In the code below you will see that it sleeps before closing the NetworkStream. If I remove the Sleep it causes an intermittent problem where the data doesn't turn up at the other end.

Am I doing something wrong here?

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();
}

Some other information:

  • On some computers you can remove the Sleep without it causing a problem (slower computers perhaps?)
  • I've tried closing the NetworkStream with Close(int timeout) (instead of sleeping) but that didn't help.
  • The 1000 millisecond value is arbitrary - I suspect that other values would work too. The question is: why is it required in the first place?

Calling close with a timeout on a NetworkStream means that the network stream will stay open in the background for X time to allow remaining data to be sent. In the background is important to note since your code is not blocked by this. Because you encapsulate the tcpClient in a using statement, the client and internally the NetworkStream will be disposed directly after your call to close. Sleep in this case works since it allows the data to be sent out and blocks your method in the meantime to prevent it from forcefully disposing of its resources.

A cleaner solution would be to set an active LingerState on the TcpClient with a long enough timeout. See: http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.lingerstate.aspx

If your receive queue is not empty (you got data in your receive buffer from the server that you haven't read, disposing the Socket (Client) sends a TCP RST (Resets the connection)) and the data in the send buffer is discarded ie if not already sent lost, otherwise it waits till the send buffer is empty and then terminates the tcp connection.

One workaround is to close the send channel:

    client.Client.Shutdown(SocketShutdown.Send)
    clientStream.Close();
}

before closing the client (instead of thread.sleep), in this case the conneciton is not reset.

Also .Flush() does nothing on a networkstream.

see: http://cs.baylor.edu/~donahoo/practical/JavaSockets/RecvQClose.pdf

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM