Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle timeout in Async Socket?

I have a code that using async socket to send message to client and expecting response from it. If the client did not reply in a specified internal it will considers timeout. Some of the article in Internet suggest to use WaitOne, but this will blocks the thread and defers the purpose of using I/O completion.

What is the best way to handle timeout in async socket?

 Sub OnSend(ByVal ar As IAsyncResult)
       Dim socket As Socket = CType(ar.AsyncState ,Socket)
       socket.EndSend(ar)

       socket.BeginReceive(Me.ReceiveBuffer, 0, Me.ReceiveBuffer.Length, SocketFlags.None, New AsyncCallback(AddressOf OnReceive), socket)

 End Sub
like image 715
kevin Avatar asked May 12 '11 04:05

kevin


1 Answers

You can’t timeout or cancel asynchronous Socket operations.

All you can do is start your own Timer which closes the Socket—the callback will then be immediately called and the EndX function will come back with an ObjectDisposedException if you call it. Here's an example:

using System;
using System.Threading;
using System.Net.Sockets;

class AsyncClass
{
     Socket sock;
     Timer timer;
     byte[] buffer;
     int timeoutflag;

     public AsyncClass()
     {
          sock = new Socket(AddressFamily.InterNetwork,
                SocketType.Stream,
                ProtocolType.Tcp);

          buffer = new byte[256];
     }

     public void StartReceive()
     {
          IAsyncResult res = sock.BeginReceive(buffer, 0, buffer.Length,
                SocketFlags.None, OnReceive, null);

          if(!res.IsCompleted)
          {
                timer = new Timer(OnTimer, null, 1000, Timeout.Infinite);
          }
     }

     void OnReceive(IAsyncResult res)
     {
          if(Interlocked.CompareExchange(ref timeoutflag, 1, 0) != 0)
          {
                // the flag was set elsewhere, so return immediately.
                return;
          }

          // we set the flag to 1, indicating it was completed.

          if(timer != null)
          {
                // stop the timer from firing.
                timer.Dispose();
          }

          // process the read.

          int len = sock.EndReceive(res);
     }

     void OnTimer(object obj)
     {
          if(Interlocked.CompareExchange(ref timeoutflag, 2, 0) != 0)
          {
                // the flag was set elsewhere, so return immediately.
                return;
          }

          // we set the flag to 2, indicating a timeout was hit.

          timer.Dispose();
          sock.Close(); // closing the Socket cancels the async operation.
     }
}
like image 50
Cory Nelson Avatar answered Nov 15 '22 23:11

Cory Nelson