Condividi tramite


Handling a timeout when reading network data

I have been involved in a number of forum posts and mail threads lately regarding reading data from a socket. The typical situation is as follows:

A TcpClient object is connected to a remote party. The application gets a reference to a NeworkStream object by calling the TCPClient’s GetStream method. The remote party begins sending messages and the NetworkStream's read method is used to read the data sent over the network. All is well so far:

Now, to avoid waiting in a blocking read call forever, one can set a timeout in the call to NetworkStream.Read( ). If no data arrives within the timeout specified, an exception is thrown.

At this point one may be tempted to catch the exception and then reissue the read on the same NetworkStream. This strategy can lead to unexpected errors. The best thing to do is to now treat the NetworkStream (socket) as being in an unstable state. This is because when the underlying stack times out, the underlying I/O read gets cancelled. If data comes in at the same time, the data will be lost, resulting in a corrupted data stream.

A better approach is to catch the exception, close the socket or TCPClient and reconnect if necessary.

TcpClient client;

NetworkStream stream;

byte[] readBuffer = new byte[1024];

try

{

// Create a TcpClient.

// Note, for this client to work you need to have a TcpServer

// connected to the same address as specified by the server, port

// combination.

Int32 port = 13000;

client = new TcpClient(server, port);

// Get a client stream for reading and writing.

// Stream stream = client.GetStream();

stream = client.GetStream();

// set read timeout

stream.ReadTimeout = 60000;

stream.Read(readBuffer,0,readBuffer.Length);

……

} catch (IOException e){

// the read timed out

// At this point the socket should be considered in a bad state.

}