recv zu string zusammenfügen



  • Hallo!
    Ich habe ein Problem mit recv. Ich habe mir eine Funktion geschrieben, um mehrere recvs zu einem string zusammenzufügen (da ja meistens der empfangene string nicht auf ein stück gelesen werden kann.
    Das ist meine Funktion:

    bool cSocket::receiveString(string& buffer)
    {
      char buf[READ_BUFFER_LEN];
      int rlen;
    
      buffer = "";
    
      do
      {
        memset(buf, '\0', READ_BUFFER_LEN);
        rlen = recv(orgSocket, buf, READ_BUFFER_LEN, 0);
    
        if (rlen == SOCKET_ERROR)
          break;
    
        buf[rlen] = '\0';
        buffer += buf;
      } while (rlen == READ_BUFFER_LEN);
    
      return true;
    }
    

    READ_BUFFER_LEN ist 256

    Ich versuche dann eine Webseite von einem normalen webserver zu empfangen, aber wenn ich den Text nach und nach empfange, ist mitten drinnen der buffer auf einmal nicht ganz gefüllt und meine schleife hört auf, ohne den ganzen string empfangen zu haben.
    Kann mir vieleicht jemand sagen, wie man so etwas richtig macht?

    MfG
    FloFri



  • Ich kenn mich mit den Netzwerkfunktionen nicht so aus, aber es ist nicht garantiert,
    dass bei jedem recv immer so viele Daten übertragen werden, wie der Buffer groß ist.
    d.h. deine while Schleife kann so auch nicht funktionieren. Teste lieber, ob überhaupt
    Daten im Buffer sind.



  • Wie wäre es hiermit

    bool cSocket::receiveString(string& arg_buffer)
    {
      string buffer;
      do
      {
        static char buf[READ_BUFFER_LEN];
        int rlen = recv(orgSocket, buf, READ_BUFFER_LEN, 0);
    
        if (rlen == SOCKET_ERROR)
          return false;
    
        buffer.append(buf, rlen);
      }while(rlen != 0);
    
      arg_buffer.swap(buffer);
      return true;
    }
    

    Der Grund wieso ich buffer ein lokale Funktion gemacht habe ist damit der Inhalt von arg_buffer definiert ist im Falle eines Fehlschlags der Funktion. Keine Angst string::swap ist exterm schnell. Eventuell wäre es eine Überlegung wert über das Werfen von Ausnahmen nachzudenken.

    Das memset ist einfach weggeworfene Performance.

    Der Grund wieso ich buf und rlen in die Schleife bewegt habe ist da man Variablen so nah wie möglich an dem Ort definieren soll wo sie gebraucht werden. buf habe ich static gemacht da ich davon ausgehe, dass READ_BUFFER_LEN recht groß sein sollte und dadurch das Risiko von Stacküberläufe vermindert wird.

    string::append hat den Vorteil, dass man nicht auf \0 aufpassen muss. Zum Beispiel muss nicht garantiert sein, dass der letzte char in buf ein \0 ist. Desweiteren kann der String der empfangen wird auch in der Mitte ein \0 enthalten da keine C-Strings im Spiel sind. Desweiteren muss append nicht über den ganzen String laufen um seine Länge zu bestimmen und kann daher die Vorteile von memcpy nutzen.



  • Danke für deine Hilfe.
    Es gibt aber noch ein Problem: (rlen != 0) ist nur false, wenn der socket geschlossen wird. Sprich, die While-Schleife bleibt beim recv hängen (blocking sockets), bis die verbindung geschlossen wird. Das müsste doch noch irgendwie anderst gehen, dass while abbricht, wenn das letzte stück des strings aus dem puffer gelesen wurde.



  • Habe mein Problem gefunden 🙂
    Das war die richtige Abbruchbedingung:

    while (buf[rlen-1] != '\0')
    

    Das Problem, dass das vorher nicht funktioniert hatte, war meine senden-funktion:

    bool cSocket::sendString(string data)
    {
      int result;
    
      result = send(orgSocket, data.c_str(), data.length(), 0);
      updateError();
    
      return (result != SOCKET_ERROR);
    }
    

    Das send muss natürlich so aussehen:

    result = send(orgSocket, data.c_str(), data.length()+1, 0);
    

    Sonst wird ja das '\0' nicht übertragen 🙂

    Danke für eure hilfe 👍


Anmelden zum Antworten