Netzwerkprogrammierung: TCP receive: Empfangene bytes?



  • Hallo,
    Bei TCP-Verbindungen benutzt man ja eine Funktion um von der aufgestellten Verbindung Daten zu empfangen.
    Das typische Vorgehen ist, dass man beim lese-Aufruf einen Buffer und maximalgrösse des Buffers angibt.
    z.B. sockets:
    int recv(int socket, char *buffer, int buf_len, int flags);
    oder Boost.Asio:
    basic_stream_socket::async_receive

    Dabei wird immer gesagt:
    Die tatsächlich zurückgelieferte Datenmenge kann beliebig sein.

    Also wie ist das wenn:
    (schematisch, im Socket-Jargon)

    B listen
    A connect zu B,
    B accept
    B send (x bytes)
    A recv (max y bytes)

    Wir gehen mal davon aus, dass x klein ist, d.h. x < MSS und x < y.
    Kann es dann unter normalen Umständen (keine Netzwerkprobleme) sein, dass A recv mit weiniger als x bytes zurückkommt??!
    Unter welchen Umständen?
    Wie löst ihr sowas in der Praxis, wenn die x bytes die B schickt nicht vorher feststehen, sondern Teil der Info von B sind?



  • Bei unterschiedlich langen Daten schickt man eigentlich immer als erstes die Länge mit (d.h. fest als short oder int). Und danach mußt du halt in einer Schleife solange Daten lesen, bis du die übergebene Länge gelesen hast.

    Sehr wenige Bytes sollten aber immer am Stück geliefert werden. Das TCP/IP-Protokoll hat dafür m.E. 12 oder 16 Bytes vorgesehen.



  • man: recv gibt dir doch die Anzahl der gelesenen Bytes zurück. Es kann immer vorkommen, dass Daten in mehreren Stücken ankommen, auch wenn x<MSS ist. zB weil das Betriebssystem des Senders die Daten zu früh los schickt (siehe TCP_CORK/Nagle) oder weil ein Gateway eine kleinere MSS hat und die Pakete fragmentiert werden müssen.

    Du kannst natürlich eine Funktion basteln, die einfach so lange versucht zu lesen, bis du wirklich x bytes gelesen hast (oder ein Fehler auftritt bzw. die Verbindung abbricht)

    int read_force(int fd, char *buf, size_t len) {
      size_t pos = 0;
      while(pos < len) {
        ssize_t got = read(fd, buf + pos, len - pos);
        if(got == 0) {
          return 0; // vorzeitig verbindung getrennt
        }
        if(got < 0) {
          if(errno == EINTR) {
            continue;
          }
          return -1; // fehler
        }
        pos += (size_t)got;
      }
      return 1; // ok
    }
    

Anmelden zum Antworten