Sunday, April 20, 2008

What is peeking in TCP and why should it be avoided

Typical network receive operation via sockets looks like this:

socket.Receive(userBuffer, userBuffer.Length, SocketFlags.None);

In the above code received data is moved from Winsock internal buffers into the buffer specified by the user. Next time when socket.Receive is called another data chunk from TCP stream will be moved into the userBuffer.



On the other hand there is a receive method that is not moving data from system to user buffer but instead copies it. This process is called peeking.


Following code is peeking data from system buffer:
socket.Receive(userBuffer, userBuffer.Length, SocketFlags.Peek);

Every time Receive is called it copies the very same data from internal (system) buffer into user buffer.

One may ask why do wee need this peeking at all and why it is present in sockets API?

Peeking was introduced to preserve compatibility with Unix BSD sockets.
So, where one can use peeking? The answer is nowhere, do not use it at all when doing network I/O. Peeking is very inefficient and must be avoided.

Monday, April 14, 2008

Change socket send and receive timeout

Sometimes synchronous Socket I/O methods like Send or Receive take too long to complete or produce an error (exception). This default behavior can be changed using socket options. Namely, SocketOptionName.SendTimeout and SocketOptionName.ReceiveTimeout.

Here's code sample how to get/set these socket options:


//get socket receive timeout
int timeout = (int)socket.GetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.ReceiveTimeout);

//set socket receive timeout
int timeout = 0;
socket.SetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.ReceiveTimeout, timeout);

Nearly the same code is for SendTimeout socket option

//get socket send timeout
int timeout = (int)socket.GetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.SendTimeout);

//set socket send send timeout
int timeout = 0;
socket.SetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.SendTimeout, timeout);


When you do not use synchronous I/O but instead use BeginXXX/EndXXX or non-blocking sockets then you can let the system handle long lasting I/O. You no longer need to handle timeouts, since your code is not waiting for the I/O to complete.

If you still want to wait for asynchronous operation to complete you can use AsyncWaitHandle property of the IAsyncResult interface.

IAsyncResult result = socket.BeginReceive(/*parameters come here*/);
//here we can wait for 5 minutes for completion of receive operation
result.AsyncWaitHandle.WaitOne(5*60*1000, false);

Thursday, April 10, 2008

Proper way to close TCP socket

This question arises very often in the developers communities.
For simplification I'll talk about synchronous sockets.

Generally, the procedure is like this:

  1. Finish sending data

  2. Call Socket.Shutdown with SocketShutdown.Send parameter

  3. Loop on Receive until it returns 0 or fails with an exception

  4. Call Close()

Here's a small sample in pseudo code that is very similar to C# :)

void CloseConnection(Socket socket)
{
socket.Send(/*last data of the connection*/);
socket.Shutdown(SocketShutdown.Send);

try
{
int read = 0;
while( (read = socket.Receive(/*application data buffers*/)) > 0 )
{}
}
catch
{
//ignore
}
socket.Close();
}

If first and third steps are skipped - data loss can happen.

Things become more complicated when using asynchronous sockets.
To prevent data loss while closing connection: termination logic can be added to the data exchange protocol.
For example, it can be some kind of termination message (depends on data protocol). When peer receives message of this kind, it can proceed with connection termination logic described above.

Another way is to put socket in a blocking mode (if socket was in non blocking mode) and close the connection in the way described above.

When designing network application one has to think also about its connection closing procedure. The purpose of proper connection close is prevention of data loss.