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.