2009-05-13 5 views
7

auf volle .Net Framework verwende ich den folgenden Code:Wie kann ich nicht-infinite Empfangen und Senden Timeouts auf einem Socket unter Compact Framework erreichen?

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

Allerdings ist Windows Mobile nicht unterstützt und löst Ausnahmen.

Ich bin gerade dabei, diese solution for implementing timeouts zu testen.

Kennt jemand einen besseren Weg? Ich möchte, wenn möglich, vermeiden, mehrere Threads zu erzeugen, das ist schließlich ein eingebettetes Gerät.

Antwort

9

Dieser Code funktioniert, Timeouts erhöhen, wenn erwartet (es ist eine modifizierte Version des Beispiels I in der Frage verbunden):

// 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); 
} 

Das entscheidende Element aus dem Beispiel fehlt fand ich ist Socket.Select(IList checkRead, IList checkWrite, IList checkError, int microSeconds). Beachten Sie, dass diese Methode die Liste ändern kann, die an sie übergeben wird (deshalb erstellt mein Code jedes Mal eine neue) und misst die Zeit in Mikrosekunden statt in Millisekunden. Und denken Sie daran, Environment.TickCount (das ist ein monotonic time source) anstelle von DateTime.Now für die Zeitmessung verwenden.

+0

Für was sind die Socket.Select Aufrufe gut? Warum nicht einfach sofort senden/empfangen und dann länger schlafen (z. B. 500 ms), wenn eine Ausnahme ausgelöst wird? –

+0

Socket.Select stellt sicher, dass der folgende Vorgang nicht blockiert wird. Wenn es nicht vorhanden wäre, würde das Ganze noch unendlich warten. – skolima

+1

socket.Poll() ist eine etwas einfachere Wahl, wenn Sie nicht auf mehrere Sockets warten müssen. –

0

Ich hatte das gleiche Problem. Dies kann behoben werden EventWaitHandle, die hier beschrieben wird post