Allgemeine Frage zu Sockets
-
hallo,
ich beschäftige mich seit kurzem mit sockets.
wie bestimmt jeder habe ich mit dem server- und clientbeispiel begonnen.es ist mir möglich, den client mit dem server zu verbinden und
"text-nachrichten" zu verschicken an den server, der diese einfach
in der konsole ausgibt.folgender pseudo-code: (client)
erstelle socket;
connecte zum server;
while(lies von der stdin) {
sende(text);
}das senden klappt nur einmal. ein weiteres senden ist nicht mehr
möglich, auch wenn ::send(...) ausgeführt wird. beim server kommt jeden-
falls nichts an.doch wenn ich den code umschreibe wie folgt:
while(lies von der stdin) {
erstelle socket;
connecte zum server;
sende(text);
}wird jede "text-eingabe" in der konsole an den server gesendet.
frage:
muss denn jedes mal ein socket erstellt und zum server eine verbindung
hergestellt werden, damit daten versendet werden können?
oder gibt es eine möglich die verbindung aufrechtzuerhalten und nur noch
durch den gebrauch von send(...) daten zu senden an den server.ich wäre sehr dankbar für tipps.
gruss
QuornJulio
-
QuornJulio schrieb:
frage:
muss denn jedes mal ein socket erstellt und zum server eine verbindung
hergestellt werden, damit daten versendet werden können?Nö, man kann auf einer Verbindung beliebig viele Daten versenden, auch mit Pausen dazwischen, auch mit Flusswechseln (Senden, Empfangen, Senden) bzw. sogar auch gleichzeitig senden und empfangen ("full duplex").
oder gibt es eine möglich die verbindung aufrechtzuerhalten und nur noch
durch den gebrauch von send(...) daten zu senden an den server.Das ist nicht nur möglich, das ist sogar "Default". Soll heissen: du musst nix spezielles machen damit das funktioniert. So lange du die Verbindung nicht mit closesocket() oder shutdown() zumachst kannst du sie verwenden um Daten zu verschicken und empfangen. D.h. du hast irgendwoanders einen Fehler drinnen.
ich wäre sehr dankbar für tipps.
Tip 1: guck dir mal den Server-Teil an, vielleicht liegt der Fehler ja dort. Ganz speziell lies dir die Dokumentation der Funktion recv() durch. recv() ist *DIE* Sockets-Funktion über die die meisten Anfänger stolpern.
Tip 2: poste den Code des Clients und Servers. Zumindest die Teile die mit Sockets zu tun haben, und 1:1 aus deinem Programm rauskopiert, ohne weitere Modifikationen.
-
hallo hustbaer,
habe mal die "wichtigsten zeilen" rausgesucht.
server.cpp sieht wie folgt aus:
#define BUFFER_SIZE 1024 int handling(SOCKET& c) { char buffer[BUFFER_SIZE]; int bytes; memset(buffer, 0, BUFFER_SIZE); bytes = recv(c, buffer, sizeof(buffer), 0); if (bytes == -1) { return -1; } buffer[bytes] = '\0'; printf("%s", buffer); return 0; } int main(int argc, char* argv[]) { ... ... ... if ((s = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { perror("socket() failed"); return EXIT_FAILURE; } int arg = 1; int sOPtionREUSE = ::setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, sizeof(int)); int sOPtionKEEP = ::setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char*)&arg, sizeof(int)); if (sOPtionREUSE == SOCKET_ERROR || sOPtionKEEP == SOCKET_ERROR) { perror("setsockopt() failed"); return EXIT_FAILURE; } struct sockaddr_in server, client; memset(&server, 0, sizeof(server)); memset(&client, 0, sizeof(client)); server.sin_addr.s_addr = htonl(INADDR_ANY); server.sin_port = htons(1975); server.sin_family = AF_INET; if (::bind(s, (sockaddr*)&server, sizeof(server)) == SOCKET_ERROR) { perror("bind() failed"); return EXIT_FAILURE; } if (listen(s, 3) == -1) { perror("listen() failed"); return EXIT_FAILURE; } int size = sizeof(client); for (;;) { c = ::accept(s, (sockaddr*)&client, &size); if (c == SOCKET_ERROR) { perror("accept() failed"); return 5; } if (handling(c) == -1) { fprintf(stderr, "%s: handling() failed", strerror(error)); } } //close(c); /* vorerst Verbindung aufrechterhalten */ return 0; }
client.cpp sieht wie folgt aus:
#define BUFFER_SIZE 1024 int handling(SOCKET& sock, char* text) { int bytes; bytes = ::send(sock, text, sizeof(text), 0); if (bytes == -1) { return -1; } return 0; } int main() { ... ... ... struct sockaddr_in server; s = ::socket(AF_INET, SOCK_STREAM, 0); if (s == -1) { perror("socket failed()"); return 2; } server.sin_addr.s_addr = inet_addr("127.0.0.1"); server.sin_port = htons(1975); server.sin_family = AF_INET; if (::connect(s, (sockaddr*)&server, sizeof(server)) == -1) { perror("connect failed()"); return EXIT_FAILURE; } char buffer[BUFFER_SIZE]; while(fgets(buffer, sizeof(buffer), stdin)) { buffer[BUFFER_SIZE] = '\0'; if (handling(s, buffer) == -1) { fprintf(stderr, "%s: error in handling()\n", strerror(errno)); return EXIT_FAILURE; } memset(buffer, 0, 50); } //close(s); /* vorerst Verbindung aufrechterhalten */ return EXIT_SUCCESS; }
danke für deine hilfe!
gruss
QuornJulio
-
Du wartest in Deiner Schleife mit 'accept' immer auf neue Verbindungen, anstatt mit einer einmal angenommenen Verbindung immer wieder zu lesen ...
-
Belli schrieb:
Du wartest in Deiner Schleife mit 'accept' immer auf neue Verbindungen, anstatt mit einer einmal angenommenen Verbindung immer wieder zu lesen ...
Naja...
Im Prinzip muss er beides tun, nen?Einerseits mit accept() auf die nächste Verbindung warten, und andrerseits mit recv() Daten empfangen. Sonst geht ja wie im Moment bloss 1x Lesen oder bloss eine Verbindung gleichzeitig. Beides nicht befriedigend.
Da beides aber nicht gleichzeitig geht, muss er entweder nen eigenen Thread pro Connection, oder einen IO-Demultiplexer ala select() oder IO-Completion Ports verwenden.
@QuornJulio
Willkommen an der Stelle wo Netzwerkprogrammierung anfängt "interessant" zu werden
-
hustbaer schrieb:
Belli schrieb:
Du wartest in Deiner Schleife mit 'accept' immer auf neue Verbindungen, anstatt mit einer einmal angenommenen Verbindung immer wieder zu lesen ...
Naja...
Im Prinzip muss er beides tun, nen?Naja ... im Moment würde ihm erst mal eine Verbindung reichen, habe ich so den Eindruck ...
-
Tjo.
Auch möglich.Übrigens @QuornJulio...
Du solltest dir doch nochmal die Doku zu recv() durchlesen.
recv() empfängt nämlich nicht notwendigerweise das auf einmal, was auf einmal mit send() weggeschickt wurde.
Sondern einfach irgendwas zwischen 1 und "Puffergrösse" Byte.
Und ich habe so irgendwie den Eindruck, als ob dir das u.U. nicht klar ist.
-
Also, um auf die Schnelle einen kleinen Schritt weiterzukommen, reicht es glaube ich aus, wenn Du aus o.g. Serverquelltext die Zeilen 55 bis 59 vor die for-Schleife packst.
Du kannst dann genau eine Verbindung entgegennehmen, von der dann in der Schleife gelesen wird.
-
QuornJulio schrieb:
#define BUFFER_SIZE 1024 int handling(SOCKET& c) { char buffer[BUFFER_SIZE]; int bytes; memset(buffer, 0, BUFFER_SIZE); bytes = recv(c, buffer, sizeof(buffer), 0); if (bytes == -1) { return -1; } buffer[bytes] = '\0'; printf("%s", buffer); return 0; }
Stichwort: Off by one
unter gewissen umbstaenden
-
Hallo,
vielen dank an alle, die geantwortet haben.
werde umsetzen/verarbeiten, worauf ihr mich hingewiesen habt.wie erwähnt, stehe ich am anfang und wollte mit einem "kleinen" beispiel
einsteigen in die socketprogrammierung. (sollte auch einfach als übung dienen)
client liest von der stdin, sendet das gelesene, server empfängt,
gibt das empfange aus und das ganze wieder von vorne.... und ich dachte: "kann doch nicht so schwer sein"
melde mich, sobald ich erste erfolge verbuchen konnte.
gruss
QuornJulio
-
C0de4Fun schrieb:
Stichwort: Off by one
unter gewissen umbstaendenStümmt.