2017-04-16 3 views
0

Ich benutze Recv auf einer grundlegenden TCP-Verbindung. Dies ist der [] Byte, das lese ich gerade: [0 4 9 0]Recv() überspringt Bytes

Hier sind die recv Anrufe und am Ende des Code im Kontext

recv(fd_serv, &len, sizeof (len), MSG_NOSIGNAL); 
len = ntohs(len); 
recv(fd_serv, &tool_id, sizeof (tool_id), MSG_NOSIGNAL); 
recv(fd_serv, rdbuf, len, MSG_NOSIGNAL); 

Wenn in gdb debuggen ich sehen kann, dass

len = 4 
tool_id = 9 
rdbuf = [ 0 4 9 0 ]/[ 0 4 \t 0 ] 

Wie ist das möglich? Es sieht so aus, als ob RECV die ersten zwei Bytes für len und das nächste Byte für tool_id (wie die Länge/Größe) nimmt, während alle Bytes für rdbuf genommen werden. Ich würde erwarten, dass es konsistent ist. Ich dachte, dies könnte ein Feature für das Lesen von Teilbyte sein, aber anscheinend liege ich falsch.

Wenn ich

recv(fd_serv, &tool_id, sizeof (tool_id), MSG_NOSIGNAL); 

aus dem Code und überprüfen RDBUF in gdb die ersten 2 Byte entfernen Änderung nach

recv(fd_serv, rdbuf, len, MSG_NOSIGNAL); 

Ausführung wird es

[ 9 0 9 0 ]/[ \t 0 \t 0 ] 

Als ich es wieder Kommentar- , das Rdbuf ist wieder normal. Zuerst dachte ich, dass die übriggebliebenen Bytes, die nicht gelesen wurden, kopiert werden. Ich habe rdbuf [3] auf 5 gesetzt und dachte, es könnte 0 dann ersetzen, aber das tat es nicht. Von jetzt an bin ich ratlos, was hier passiert und warum es hier widersprüchlich ist.

Ich bin mit Arch Linux x86_64 gdb 7.12.1, gcc 6.3.1 und diese zu bauen:

gcc -g -DDEBUG *.c -o client.dbg -lcrypto 

Kontext

while(TRUE) { 
    if (fd_serv != -1 && FD_ISSET(fd_serv, &fdsetrd)) { 
     int n; 
     uint16_t len; 
     uint8_t tool_id; 
     char rdbuf[1024]; 

     errno = 0; 
     n = recv(fd_serv, &len, sizeof (len), MSG_NOSIGNAL | MSG_PEEK); 
     if (n == -1) { 
      if (errno == EWOULDBLOCK || errno == EAGAIN || errno == EINTR) 
       continue; 
      else 
       n = 0; 
     } 

     if (n == 0) { 
      close_connection(); 
      continue; 
     } 

     if (len == 0) { 
      recv(fd_serv, &len, sizeof (len), MSG_NOSIGNAL); 
      continue; 
     } 
     len = ntohs(len); 
     if (len > sizeof (rdbuf)) { 
      close(fd_serv); 
      fd_serv = -1; 
     } 

     errno = 0; 
     n = recv(fd_serv, rdbuf, len, MSG_NOSIGNAL | MSG_PEEK); 
     if (n == -1) { 
      if (errno == EWOULDBLOCK || errno == EAGAIN || errno == EINTR) 
       continue; 
      else 
       n = 0; 
     } 

     if (n == 0) { 
      close_connection(); 
      continue; 
     } 

     recv(fd_serv, &len, sizeof (len), MSG_NOSIGNAL); 
     len = ntohs(len); 
     recv(fd_serv, &tool_id, sizeof (tool_id), MSG_NOSIGNAL); 
     recv(fd_serv, rdbuf, len, MSG_NOSIGNAL); 

     printf("%d\n", tool_id); 
    } 
} 
+2

Sie müssen immer den Rückgabewert von 'recv()' überprüfen. Es sagt Ihnen nicht nur über Fehler, aber es sagt Ihnen, wie viele Bytes tatsächlich von dem Aufruf zurückgegeben wurden. –

Antwort

1

den Rückgabewert von recv Überprüfung hilft in diesem Fall (als Antwort auf Michael Burrs Kommentar). Ich kam zu dem Schluss, dass der letzte Recv-Aufruf nicht alle Bytes liest, sondern nur die übrig gebliebenen. Die sind in diesem Fall entweder 1 oder 2. Die Bytes werden dann am Anfang platziert, während die alten Werte nicht überschrieben werden. Ich denke, diese Kombination hat mich verwirrt.