2
votes

I'm developing a server application in C#. Clients can connect to the server and make various requests. Currently, when a client connects I spawn a new thread to handle the request(s). I'm using the TCPClient class to handle client connections. My server works as follows:

  1. Client connect to server with a request
  2. Server handles request
  3. Server waits to see if client has any more requests
  4. If client does not make another request within some timeout period, the server kills the connection

My problem is the following:

When I read from the NetworkStream object that I get from the TCPClient class, the NetworkStream Read() method does not block if there is no Data Available. When the server reaches step #3, I would like to set some timeout on the NetworkStream and if the client does not make any more requests within that duration the server should kill the connection when that timeout exception is thrown. When my server reaches step 3, the NetworkStream Read() method does not block, reguardless of what I set it's ReadTimeout property to be. Can anyone help me out, or suggest a better way to do what I'm trying to do.

Thanks

6
Could you use UDP instead and make it connectionless?user47589

6 Answers

2
votes

NetworkStream.Read and ReadByte should block until the timeout if there's no data to read. I think it's far more likely that the call is reading something, probably a bunch of zeroes. Check the data being sent by the client carefully.

0
votes

Wrap the NetworkStream in a BufferedStream. BufferedStream.Read will block until at least 1 byte is available.

0
votes

You should graduate from using Read() to the BeginRead() method and look into parallel processing. Network programming is not for the faint of heart.

Basically you don't want to create a loop polling for data.

while(!timedout && !stream.DataAvailable) sleep(0); // This is bad.
if(steam.DataAvailable) steam.Read();

Instead it makes more sense to do something like this. Create a reset event, call BeginRead(), and release the reset event on the callback. Something like the following:

void clientThread()
{
   stream.BeginRead(myCallback);
   resetEvent.WaitOne(timeout)
}
void myCallback
{
   resetEvent.Set();
}
0
votes

Is this what you're looking for?

http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.receivetimeout.aspx

Looks like you get the NetworkStream from the TcpClient using GetStream(), then call the Read() method on it.

0
votes

To explicitly force the NetworkStream to block when there is no available data:

TcpClient clientConnection = new TcpClient();

if(clientConnection.Available > 0)
{ 
  //You want to continue execution even though there is no available data to be read from the server then:
  clientConnection.Client.Blocking = false;
}
-1
votes

You'll need to handle the "timeout" yourself, since NetworkStream.Read() doesn't provide a way to do that.

What you'll probably want to do in your client thread is use some combination of NetworkStream.DataAvailable and/or NetworkStream.CanRead in conjunction with a blocking/timeout mechanism (such as using a WaitHandle.WaitOne call with a timeout) to provide the client with time to make data available. If nothing comes in after a specified time, just shutdown the connection, and exit.