2017-09-07 8 views
0

Ich implementieren TCP-Socket-Kommunikation mit Epoll, um alle Client-Ereignisse zu überwachen, verarbeitet nur ein Thread alle Client in einer for-Schleife. Jeder Sockel ist nicht blockierend.tcp Socket Recv zurück "Ressource vorübergehend nicht verfügbar", wenn recv buf bereits Daten haben

jetzt erlitt ich nur ein Problem, wenn Client Daten mehr als MTU senden, bedeutet mehrere Fragment-Paket, Server kann immer nicht alle Daten vollständig lesen. wie unten lese ich den kopf zuerst, bekomme die pdu len vom kopf, lese dann den pdu teil.

Das Problem ist, obwohl ich den Kopf erfolgreich lesen, dicht gefolgt mit dem PDU recv(), aber es immer EAGAIN mehrmals zurück. Also wird meine Wiederholung brechen. Da der Server tausende Client-Ereignisse verarbeiten muss, denke ich, dass es ein großer Leistungsverbrauch ist, den Wiederholungsversuch immer fortzusetzen, was nicht tolerierbar ist.

Ich benutze tcpdump Erfassen der Pakete vom Client, jedes Paket ist Fragment bis maximal 1448 Bytes Daten, aber Kopf ist nur 5 Bytes, warum kann ich den Kopf erfolgreich lesen, aber die folgenden Daten recv() Operation wird EAGAIN zurückgeben? Ist es möglich, recav EAGAIN zurückzugeben, wenn bereits Daten im Recv-Puffer ankommen? Meiner Meinung nach kann ich die ersten 5 Bytes lesen, also müssen mehr Daten im recv-Puffer gelesen werden.

möglicherweise mit dem Assembly-Prozess in TCP/IP-Stack verwandt. code ist wie unten, jeder pdu recv, muss 10 oder mehr versuchen, vielleicht erfolg.

... 
#define HDR_LEN 5 
n = epoll(epfd, events, 1000, -1) 
for(i =0; i < n; i++) 
{ 
    uint8 pHdr[HDR_LEN] = {0}; 
    uint16 pdulen = 0, offset =0; 
    infd = events[i].fd; 
    nRead = recv(infd, pHdr, HDR_LEN); // read the data head first 
    pdulen = ntohs(*(uint16 *)(pHdr+2)); // get the pdu len from the head 
    uint8 *pbuf = malloc(pdulen+HDR_LEN); 

    memcpy(pbuf, pHdr, HDR_LEN);   // move the head to buf 
    while(offset != pdulen)     // then read the pdu data 
    { 
     nRead = recv(infd, pbuf+HDR_LEN+offset, pdulen-offset); 
     if (nRead <=0) 
     { 
      if (nRead == -1 && errno == EAGAIN) // resource temporarily unavailable 
      { 
       if (retry < 5) 
       { 
        usleep(500); 
        retry++; 
        continue; 
       } 
       else 
        break; // already try 5 times, should always continue? 
      } 
      else 
       break; 
     } 
     else 
     { 
      offset += nRead; 
      retry = 0; 
     } 
    } 
    if (offset == pdulen) 
     process(pbuf, pdulen+HDR_LEN); // process the complete data 
    ... 
} 
... 
+0

bitte etwas Hilfe, helfen Sie aus diesem Problem heraus! – jackxie

+1

Ist Ihr Socket im nicht blockierenden Modus? Wenn dies der Fall ist, ist EAGAIN zu erwarten, wenn im Empfangspuffer keine Daten mehr verfügbar sind. Um nicht-blockierende E/A von mehreren Sockets gleichzeitig zu handhaben, müssen Sie einen Zustandsautomaten implementieren, so dass Sie Ihren normalen Aufruf von poll() zurückholen können, nachdem Sie eine teilweise Antwort erhalten haben. Wenn dann poll() anzeigt, dass auf Ihrem Socket mehr Daten zu lesen sind, dann sollten Sie (und nur dann) die zusätzlichen Daten aus dem Socket zurückholen und recv() anfügen, bis Sie die Daten, die Sie von diesem Socket erhalten haben Du hast die ganze PDU. –

+0

'Will TCP-Socket Recv "Ressource vorübergehend nicht verfügbar" zurückgeben, wenn recv buf bereits Daten haben? Nein. – EJP

Antwort

0

epoll wird Ihnen sagen, wenn Sie können recv ohne blockieren, einmal. Wenn recv alle Daten vom Socket verbraucht, wird der nächste recv solange blockiert, bis mehr Daten vorhanden sind, oder EAGAIN (falls nicht blockierender Socket) zurückgegeben.

ein gemeinsames Muster ist:

  1. Verwenden select/poll/epoll zu erkennen, wenn eine Steckdose kann gelesen werden.
  2. recv einmal auf einem bereiten Sockel aufrufen und empfangene Daten an einen Puffer anhängen.
  3. Überprüfen Sie, ob der Puffer genügend Daten für die Verarbeitung enthält. Wenn ja, dann verarbeiten. Ansonsten lassen Sie select/poll/epoll sagen, wenn Sie mehr lesen können.