Как справиться с таймаутом в Async Socket? - PullRequest
7 голосов
/ 12 мая 2011

У меня есть код, который использует асинхронный сокет для отправки сообщения клиенту и ожидает ответа от него.Если клиент не ответил в указанном внутреннем сообщении, он будет считать тайм-аут.Некоторые статьи в Интернете предлагают использовать WaitOne, но это блокирует поток и откладывает цель использования завершения ввода-вывода.

Каков наилучший способ обработки тайм-аута в асинхронном сокете?

 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

1 Ответ

7 голосов
/ 12 мая 2011

Вы не можете установить тайм-аут или отменить асинхронные Socket операции.

Все, что вы можете сделать, это запустить свой собственный Timer, который закрывает Socket - обратный вызов будет немедленно вызван и *Функция 1006 * вернется с ObjectDisposedException, если вы ее вызовите.Вот пример:

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.
     }
}
...