2009-05-13 5 views
7

En .Net Framework completo uso el siguiente código:¿Cómo puedo lograr tiempos de espera de recepción y envío no infinitos en un socket en Compact Framework?

socket.SetSocketOption(
    SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, readTimeout); 
socket.SetSocketOption(
    SocketOptionLevel.Socket, SocketOptionName.SendTimeout, writeTimeout); 

Sin embargo, Windows Mobile no es compatible con esta tiros y excepciones.

Actualmente estoy en el medio de probar este solution for implementing timeouts.

¿Alguien conoce una mejor manera? Me gustaría evitar generar múltiples hilos si es posible, este es un dispositivo integrado después de todo.

Respuesta

9

Este código funciona, aumentando los tiempos de espera cuando se esperaba (que es una versión modificada del ejemplo he vinculado en la pregunta):

// copied from Mono, because CF lacks this enum 
enum SocketError 
{ 
    IOPending = 997, 
    NoBufferSpaceAvailable = 10055, 
    TimedOut = 10060, 
    WouldBlock = 10035 
} 

// milliseconds 
int receiveTimeout = 20000; 
int sendTimeout = 20000; 

public override int Read(byte[] buffer, int offset, int size) 
{  
    int startTickCount = Environment.TickCount; 
    int received = 0; 
    do 
    { 
     List<Socket> sock = new List<Socket>(new Socket[] {socket}); 
     Socket.Select(sock, null, null, receiveTimeout*1000 + 1); 
     if (Environment.TickCount > startTickCount + receiveTimeout) 
      throw new SocketException((int) SocketError.TimedOut); 
     try 
     { 
      received += socket.Receive(buffer, offset + received, 
       size - received, SocketFlags.None); 
     } 
     catch (SocketException ex) 
     { 
      if (ex.ErrorCode == (int) SocketError.WouldBlock || 
       ex.ErrorCode == (int) SocketError.IOPending || 
       ex.ErrorCode == (int) SocketError.NoBufferSpaceAvailable) 
      { 
       // socket buffer is probably empty, wait and try again 
       Thread.Sleep(30); 
      } 
      else 
       throw; // any serious error occurr 
     } 
    } while (received < size); 
    return received; 
} 

public override void Write(byte[] buffer, int offset, int size) 
{ 
    int startTickCount = Environment.TickCount; 
    int sent = 0; 
    do 
    { 
     List<Socket> sock = new List<Socket>(new Socket[] {socket}); 
     Socket.Select(null, sock, null, sendTimeout*1000 + 1); 
     if (Environment.TickCount > startTickCount + sendTimeout) 
      throw new SocketException((int) SocketError.TimedOut); 
     try 
     { 
      sent += socket.Send(buffer, offset + sent, 
       size - sent, SocketFlags.None); 
     } 
     catch (SocketException ex) 
     { 
      if (ex.ErrorCode == (int) SocketError.WouldBlock || 
       ex.ErrorCode == (int) SocketError.IOPending || 
       ex.ErrorCode == (int) SocketError.NoBufferSpaceAvailable) 
      { 
       // socket buffer is probably full, wait and try again 
       Thread.Sleep(30); 
      } 
      else 
       throw; // any serious error occurr 
     } 
    } while (sent < size); 
} 

El elemento crucial que falta en el ejemplo que he encontrado es Socket.Select(IList checkRead, IList checkWrite, IList checkError, int microSeconds). Tenga en cuenta que este método puede modificar la lista que se le pasa (es por eso que mi código crea uno nuevo cada vez) y mide el tiempo en microsegundos en lugar de milisegundos. Y recuerde utilizar Environment.TickCount (que es monotonic time source) en lugar de DateTime.Now para medir el tiempo.

+0

¿Para qué sirven las llamadas Socket.Select? ¿Por qué no simplemente Enviar/Recibir inmediatamente y luego dormir más tiempo (por ejemplo, 500 ms) cuando se lanza una excepción? –

+0

Socket.Select asegura que la siguiente operación no se bloqueará. Si no estuviera presente, toda la cosa aún esperaría infinitamente. – skolima

+1

socket.Poll() es una opción un poco más simple, si no necesita esperar múltiples sockets. –

0

Tuve el mismo problema. Esto se puede solucionar incluyendo un EventWaitHandle que se describe aquí post

Cuestiones relacionadas