recv() - lange Strings empfangen



  • Hallo,

    Ich versuche einen HTML-GET-Request, den ich über send() abgesetzt habe per recv() und strncat() zu einem langen string (src) zusammenzufassen um diesen dann auszuwerten. Jedoch kommt es Abschnittsweise zu Fehlern(einfach falscher Inhalt, richtiger text aber falsche stelle) im string "src".

    #define TERM_OFFSET 1
    
    ...
    
    int len=0;
    char *src=NULL;
    char buffer[1024];
    
    ...
    
        src="";
        while(recv(socket,buffer,sizeof(buffer)-TERM_OFFSET,0)>0)
        {
        buffer[sizeof(buffer)]='\0';
        len=strlen(src)+strlen(buffer)+TERM_OFFSET;
        if(len==sizeof(buffer)){src=NULL;printf("NULL");}//Falls erster durchlauf
        src=(char *)realloc(src,((len)*sizeof(char)));//Speicher anpassen
        if(len==sizeof(buffer)){src[0]='\0';}//Falls erster durchlauf
        strncat(src,buffer,sizeof(buffer));
        src[len-TERM_OFFSET]='\0';
        }
    
    ...
    

    Wie gesagt läuft wunderbar durch, aber vereinzelt stimmen Abschnitte in src nicht.

    Wie kann das sein, verwende ich recv() falsch? Komme nicht weiter..
    Danke im Vorraus



  • Was ich auf den ersten Blick sagen kann:

    buffer[sizeof(buffer)]='\0';
    

    erzeugt undefiniertes Verhalten. Der letzte gültige Index in buffer ist sizeof(buffer) - 1.

    Ferner wird hier:

    len=strlen(src)+strlen(buffer)+TERM_OFFSET;
        if(len==sizeof(buffer)){src=NULL;printf("NULL");}//Falls erster durchlauf
    

    im ersten Durchlauf len immer strlen(buffer) + 1 sein, weil src == "" und TERM_OFFSET == 1.

    Dementsprechend wird danach

    src=(char *)realloc(src,((len)*sizeof(char)));//Speicher anpassen
    

    undefiniert, weil src auf ein String-Literal zeigt, und

    if(len==sizeof(buffer)){src[0]='\0';}//Falls erster durchlauf
    

    wird im ersten Durchlauf ebenfalls nicht anschlagen, weil len unverändert ist (s.o.). Außerdem ist

    strncat(src,buffer,sizeof(buffer));
    

    gleichbedeutend mit

    strcat(src, buffer);
    

    ...da du, wenn in buffer mehr als sizeof(buffer) Zeichen stehen, eh schon knietief in Problemen steckst. Das ist hier aber insofern nicht richtig kritisch, als dass du, wenn der restliche Kram erstmal behoben ist, in src genug Platz haben solltest, um buffer anhängen zu können.

    Allerdings ist strncat bzw. strcat da natürlich eine wenig performante Methode; recv gibt ja die Anzahl der erhaltenen Bytes zurück, und damit kannst du die neue Endposition direkt bestimmen. Wenn ich deine Speicherstrategie richtig lese, ginge das beispielsweise so:

    #define BLOCKSIZE 1024
    
    char   *src            = NULL;
    size_t  pos            = 0;
    ssize_t bytes_received = 0;
    
    do {
      char *new_src;
    
      /* Neue Schreibposition bestimmen. Im ersten Durchlauf bleibt pos == 0 */
      pos += bytes_received;
    
      /* Sicherstellen, dass hinter src + pos immer BLOCKSIZE + 1 Zeichen verfügbar sind */
      new_src = realloc(src, pos + BLOCKSIZE + 1);
    
      if(new_src == NULL) {
        /* TODO: Fehlerbehandlung entsprechend Bedürfnissen anpassen */
        free(src);
        exit(-ENOMEM);
      }
    
      src = new_src;
    
      /* Dann können hier bis zu BLOCKSIZE Zeichen gelesen werden */
      bytes_received = recv(socket, src + pos, BLOCKSIZE, 0);
    } while(bytes_received > 0);
    
    /* und es ist noch Platz für den Sentinel. */
    src[pos] = '\0';
    

    Code ungetestet; ggf. dürfen Syntaxfehler behalten werden.


Anmelden zum Antworten