2010-05-31 11 views
7

Ich möchte recv syscall mit nonblocking Flags MSG_NONBLOCK verwenden. Mit diesem Flag kann syscall jedoch zurückkehren, bevor die vollständige Anforderung erfüllt ist. So,recv mit MSG_NONBLOCK und MSG_WAITALL

  • kann ich MSG_WAITALL Flag hinzufügen? Wird es nicht blockierend sein?
  • oder wie soll ich recv in die Schleife mit nonblocking recv neu schreiben Blockierung
+0

Denken Sie, Sie wollen Benutzer-Prozess-Speicher (um die unvollständige Nachricht zu puffern), so dass Sie Kernel-Speicher verwenden möchten. Ich bezweifle, dass es funktionieren würde. –

Antwort

3

EDIT:

Plain recv() gibt, was zum Zeitpunkt des Anrufs bis zu dem gewünschten im TCP-Puffer Anzahl der Bytes. MSG_DONTWAIT verhindert nur das Blockieren, wenn überhaupt keine Daten bereit sind, auf dem Socket gelesen zu werden. MSG_WAITALL fordert eine Blockierung an, bis die gesamte Anzahl der angeforderten Bytes gelesen werden kann. Sie werden also nicht "alles oder nichts" Verhalten bekommen. Im besten Fall sollten Sie EAGAIN erhalten, wenn keine Daten vorhanden sind, und blockieren, bis die vollständige Nachricht verfügbar ist.

Sie könnten etwas aus MSG_PEEK oder ioctl() mit einem FIONREAD gestalten (wenn Ihr System dies unterstützt), das sich effektiv wie gewünscht verhält, aber ich weiß nicht, wie Sie Ihr Ziel erreichen können, indem Sie einfach recv() verwenden Flaggen.

+1

NONBLOCK kann mit nur einem Teil der erforderlichen Nachricht zurückkehren. Ich möchte EAGAIN Formular non-blocking recv bekommen, wenn es nur einen Teil von msg zurückgeben will. Also, ich möchte nonblocking recv mit "alles oder nichts" Verhalten – osgx

4

Dies ist, was ich für das gleiche Problem haben, aber ich würde eine Bestätigung, dass dieser wie erwartet funktioniert ...

ssize_t recv_allOrNothing(int socket_id, void *buffer, size_t buffer_len, bool block = false) 
{ 
    if(!block) 
    { 
     ssize_t bytes_received = recv(socket_id, buffer, buffer_len, MSG_DONTWAIT | MSG_PEEK); 

     if (bytes_received == -1) 
      return -1; 

     if ((size_t)bytes_received != buffer_len) 
      return 0; 
    } 

    return recv(socket_id, buffer, buffer_len, MSG_WAITALL); 
} 
2

Für IPv4 TCP zumindest unter Linux empfängt, wird MSG_WAITALL wenn MSG_NONBLOCK ignoriert wird angegeben (oder der Dateideskriptor ist auf nicht blockierend gesetzt).

Von tcp_recvmsg() in net/ipv4/tcp.c im Linux-Kernel:

if (copied >= target && !sk->sk_backlog.tail) 
     break; 

if (copied) { 
     if (sk->sk_err || 
      sk->sk_state == TCP_CLOSE || 
      (sk->sk_shutdown & RCV_SHUTDOWN) || 
      !timeo || 
      signal_pending(current)) 
       break; 

Ziel in dieser Besetzung wird auf auf die gewünschte Größe, wenn MSG_DONTWAIT angegeben ist oder einem kleineren Wert (zumindest 1) wenn nicht. Die Funktion wird abgeschlossen, wenn:

  1. genug Bytes kopiert wurden
  2. Es gibt einen Socket-Fehler
  3. der Socket geschlossen wurde oder Abschaltung
  4. timeo 0 (Buchse nicht blockierend eingestellt ist)
  5. es gibt ein Signal für den Prozess, um mich

dies scheint es wie ein Fehler in Linux sein kann, aber so oder so anhängige es, wie Sie wollen nicht arbeiten. Es sieht aus wie dec-vt100's Lösung, aber es gibt eine Race-Bedingung, wenn Sie versuchen, von demselben Socket in mehr als einem Prozess oder Thread zu empfangen.
Das heißt, ein anderer recv() -Aufruf durch einen anderen Thread/Prozess kann auftreten, nachdem der Thread einen Peek ausgeführt hat, was dazu führt, dass der Thread auf der zweiten recv() blockiert wird.