Problem mit recv bei Socket
-
Geqoo schrieb:
strcpy(sendbuf, "Test", sizeof(sendbuf), 0);
Was wird das?
Hast du das compiliert bekommen?
Falls <sendbuf> kein Array ist, in das Verhalten undefiniert.Geqoo schrieb:
recvbuf[bytesRecv] = '\0';
Falls bytesRecv==250 (==sizeof recvbuf) führt auch dieses zu undefiniertem Verhalten.
-
Wutz schrieb:
Geqoo schrieb:
strcpy(sendbuf, "Test", sizeof(sendbuf), 0);
Was wird das?
Hast du das compiliert bekommen?
Falls <sendbuf> kein Array ist, in das Verhalten undefiniert.Ja, das habe ich kompiliert bekommen. Sendbuf ist genau wie Recfbuf
char sendbuf[250];
Wutz schrieb:
Geqoo schrieb:
recvbuf[bytesRecv] = '\0';
Falls bytesRecv==250 (==sizeof recvbuf) führt auch dieses zu undefiniertem Verhalten.
Die Nachrichten werden nie so lang sein, das ist jetzt nur, damit ich den Rest des Strings abschneiden kann, den ich nicht brauche.
-
Wutz meinte wohl eher dass du die Größe deiner Nachricht vorher überprüfen solltest, bevor du den string kopierst und dein stringendezeichen setzt... so könnte man potentielle Fehlerquellen minimieren (wenn man denn will...)
-
Geqoo schrieb:
Wutz schrieb:
Geqoo schrieb:
strcpy(sendbuf, "Test", sizeof(sendbuf), 0);
Was wird das?
Hast du das compiliert bekommen?
Falls <sendbuf> kein Array ist, in das Verhalten undefiniert.Ja, das habe ich kompiliert bekommen. Sendbuf ist genau wie Recfbuf
Ich staune! Ich kenne keine Implementierung von strcpy, die eine von zwei verschiedene Anzahl an Parametern nimmt.
Zum recv:
Du kannst Dich nicht darauf verlassen, daß wenn der Server zB 100 Byte mit einem send schickt, Du die auch mit einem recv bekommst.
Bei Deiner Vorgehensweise kann also folgendes passieren:Server sendet 100 Byte.
Dein Client macht einmal recv, bekommt 60 Byte, macht seine Ausgabe, schickt irgendwas zum Server zurück und beim nächsten Schleifendurchlauf macht er wieder recv und bekommt jetzt erst mal die Byte 61 - n vom ersten send.Vielleicht ist Dir das ja bekannt, aber da Du nach jedem recv eine Antwort zum Server sendest, ohne zu wissen, ob die Übertragung vollständig ist, vermute ich, daß Du da nicht drauf vorbereitet bist.
Bei einem blockierenden Socket ist dieses Verhalten beim send übrigens anders, d.h. ein send (a, b, 100, 0) sendet auf jeden Fall 100 Byte.Edit: Noch was zu Deiner ursprünglichen Frage:
Dein send/recv - Paar weiß ja nicht, daß Du einen String versendest. Für die Programme (Server/Client) ist das lediglich eine Bytefolge. D.h. wenn der Sender das einen String abschließende Nullbyte nicht mitsendet, kommt es auch nicht beim Empfänger an. Du kannst also entweder send(a, b, strlen(b) + 1, 0) machen, dann wird das 0-Byte mitgeschickt, oder aber vor dem recv den Empfangsbereich mit Nullen initialisieren, dann steht auf jeden Fall immer eine Null hinter den empfangenen Bytes.
Bei Deiner Routine ist die erstgenannte Methode riskant, weil wie gesagt es nicht garantiert ist, daß ein einziger recv alles gesendete liest.
-
Also das mit dem strcopy funktioniert, compiler meckert auch nicht..
Ok, danke soweit -> Hab ich mir zu Herzen genommen.Allerdings hab ich jetzt ein anderes Problem.
Ich definier mir hier ein struct:
typedef struct _userlist { char username[20]; char ip[15]; } userstruct;
und in der main Routine definiere ich
userstruct userlist[MAX_CLIENTS];
MAX_CLIENTS ist 100. Bei einem Login ist der Code wie folgt:
userlist[i].username[0] = token[3]; userlist[i].ip[0] = token[1]; printf("User %s [%d: %s] logged in.\n", token[3], i, token[1]);
Keine Fehler. Beim Logout:
printf("User %s logged out.\n", userlist[i].username[0]);
Und dann stürzt das Programm ab. Ich vermute mal, dass es daran liegt, dass in userlist[i].username[0] nichts drinsteht, aber wie löse ich das Problem?
-
Das Problem ist, dass du versuchst Strings mit Hilfe des Zuweisungsoperators zu kopieren... stattdessen solltest dus mal mit strcpy versuchen, das du ja selbst schon verwendet hast in deinem code
-
Jetzt bin ich soweit.
strncpy(userArray[i].ip, token[1], strlen(token[1])); userArray[i].ip[strlen(token[1])] = '\0';
Dankeschön!
Jetzt ist mir aber aufgefallen, wenn sich jemand verbindet und sich ein 2. Client direkt danach verbindet, kommen zwar die Nachrichten "Neuen Client angenommen [ID]", aber der Server schließt sich einfach, wenn der erste eine Nachricht sendet. Ich denke, es liegt daran, dass er irgentwie ne Nachricht vom anderen zuerst erwartet, aber wie bekomme ich das in den Griff?
Code:WSADATA wsa; long rc; SOCKET acceptSocket; SOCKADDR_IN addr; char sendbuf[250]; char recvbuf[250]; FD_SET fdSet; SOCKET clients[MAX_CLIENTS]; int i, j, k, l = 0; int bytesSent; int bytesRecv = SOCKET_ERROR; char zeichen[251], *token[250]; // StartUp, Erstellung, Bind, Listen ... for(i=0;i<MAX_CLIENTS;i++) { clients[i] = INVALID_SOCKET; } while (1) { FD_ZERO(&fdSet); // Inhalt leeren FD_SET(acceptSocket,&fdSet); for(i=0;i<MAX_CLIENTS;i++) { if(clients[i] != INVALID_SOCKET) { FD_SET(clients[i],&fdSet); } } rc = select(0,&fdSet,NULL,NULL,NULL); if(rc == SOCKET_ERROR) { printf("Fehler: select, fehler code: %s\n",WSAGetLastError()); return 1; } if(FD_ISSET(acceptSocket,&fdSet)) { for(i=0;i<MAX_CLIENTS;i++) { if(clients[i]==INVALID_SOCKET) { clients[i]=accept(acceptSocket,NULL,NULL); printf("Neuen Client angenommen (%d)\n",i); break; } } } for(i=0;i<MAX_CLIENTS;i++) { if(clients[i] == INVALID_SOCKET) { continue; } if(FD_ISSET(clients[i],&fdSet)) { bytesRecv = recv(clients[i], recvbuf, sizeof(recvbuf), 0); } if(bytesRecv == 0 || bytesRecv == SOCKET_ERROR) { // Code hier } else { recvbuf[bytesRecv] = '\0'; token[0] = strtok(recvbuf, ","); token[1] = strtok(NULL, ","); token[2] = strtok(NULL, ","); token[3] = strtok(NULL, ","); // Userliste erstellen l = 0; for (j=0;j<MAX_CLIENTS;j++) { if (clients[j] != INVALID_SOCKET) { if (l == 0) { strncpy(userlistbuf, userArray[j].username, strlen(userlistbuf)); } else { strncpy(userlistbuf, strcat(userlistbuf, ","), strlen(userlistbuf)); strncpy(userlistbuf, strcat(userlistbuf, userArray[j].username), strlen(userlistbuf)); } l++; } } // Ende Userliste erstellen // ..... for (k=0;k<MAX_CLIENTS;k++) { if (clients[k] != INVALID_SOCKET) { bytesSent = send(clients[k],sendbuf,strlen(sendbuf),0); printf("%d Bytes sent.", bytesSent); } } } }
Nachdem ich mal gesucht habe, weiß ich schonmal, dass dieser Teil hier die Fehlerquelle ist:
// Userliste erstellen l = 0; for (j=0;j<MAX_CLIENTS;j++) { if (clients[j] != INVALID_SOCKET) { if (l == 0) { strncpy(userlistbuf, userArray[j].username, strlen(userlistbuf)); } else { strncpy(userlistbuf, strcat(userlistbuf, ","), strlen(userlistbuf)); strncpy(userlistbuf, strcat(userlistbuf, userArray[j].username), strlen(userlistbuf)); } l++; } } // Ende Userliste erstellen
Im Else Zweig der Schleife stürzt das Programm durch den 2. strncpy ab. Was mache ich da falsch?
-
Also zunächst mal kopierst Du zweimal hintereinander etwas in den Bereich userlistbuf. Mit dem zweiten strncpy überschreibst Du also zumindest teilweise das, was Du mit dem ersten kopiert hast, das ist vermutlich nicht beabsichtigt und überflüssig.
Dann, was soll dieses Konstrukt
strncpy(userlistbuf, strcat(userlistbuf, ","), strlen(userlistbuf));
eigentlich tun.Ich denke, es hängt ein ',' an den bereits vorhandenen Inhalt von userlistbuf an, und kopiert dann userlistbuf nach userlistbuf!?
Ich vermute, daß das gleiche Ergebnis erzielt wird mit einem einfachen
strcat(userlistbuf, ",");Danach dann noch
strcat(userlistbuf, userArray[j].username);und das Ergebnis sollte wie gewünscht aussehen. Wenn bei der zweiten Instruktion das Programm abstürzt, ist eventuell userlistbuf zu klein?
-
Belli hat dein "komisches" strncpy Konstrukt schon angesprochen, des weiteren verwendest du strlen in strncpy...
-> beim 1. strncpy (das KEIN Stringendezeichen anfügt) ist das kein Problem
-> beim 2. strncpy liefert strlen aber keinen definierten Wert mehr, da du im ersten Schritt das Stringendezeichen vergisst... auch wenn du danach mit strcat arbeiten willst musst du nach deinem strncpy ein Stringendezeichen anfügen
-
Jep, funktioniert. War ja auch ein Deppenfehler
Danke euch!