[Winsock] Problem mit select() und Cleanup-Frage
-
Hi,
ich möchte gerne einen Server schreiben der eine Nachricht nach folgenden Aufbau verarbeiten kann:
Nachrichtenlänge\n Anderes Zeug\n DatenDazu habe ich mir folgende Funktionen geschrieben:
long recvLine(SOCKET s, std::string& recv) { std::stringstream buf; long rc = readLine(s, buf); if (rc == 0 || rc == SOCKET_ERROR) { closesocket(s); s = INVALID_SOCKET; std::cout << "Verbindung getrennt." << std::endl; } else { recv = buf.str(); } return rc; } long readLine(SOCKET s, std::stringstream& line) { long rc; for (char c; (rc = recv(s, &c, 1, 0)) > 0; line << c) { if (c == '\n') { return rc; } } return rc; }Diesen rufe ich hier auf:
// ... if (clients[i] == INVALID_SOCKET) { continue; } if (FD_ISSET(clients[i], &fdSet)) { std::string line; rc = recvLine(clients[i], line); if (!line.empty()) { std::cout << "Len: " << line << std::endl; rc = recvLine(clients[i], line); if (!line.empty()) { std::cout << "Other: " << line << std::endl; // - Später die eigentlichen Daten hier empfangen -// } } } // ...Das funktioniert auch, aber wenn ich die Verbidung trenne, dann scheint select() ein SOCKET_ERROR zurückzugeben. Das ist aber wahrscheinlich unschön, da man es irgendwie vermeiden kann. Leider weiß ich nicht, wie ich das vermeiden kann und warum dieser Fehler überhaupt auftritt. Wie kann ich das Problem lösen?
Dann hätte ich noch eine Frage:
Sollte ich am Ende des Programms trotz der Endlosschleife ein WSACleanup() ausführen und auch alle Sockets schließen oder ist das wegen der Endlosschleife überflüssig? Ich meine, natürlich wird dieser Code nie ausgeführt, aber ist es guter Stil diesen Aufräum-Code trotzdem zu schreiben?
Würde mich über Antworten sehr freuen.
Viele Grüße,
David K.
-
Es ist schlechter Stil, Code zu schreiben, der nie ausgeführt wird.
Es ist aber auch schlechter Stil, Programme zu schreiben, die man nicht beenden kann
-
hustbaer schrieb:
Es ist schlechter Stil, Code zu schreiben, der nie ausgeführt wird.
Es ist aber auch schlechter Stil, Programme zu schreiben, die man nicht beenden kann
Damit wäre die Frage ja dann beantwortet. Danke

Hat noch jemand eine Idee für mein eigentliches Problem? Konnte es leider noch immer nicht lösen...
-
Hat niemand eine Idee?

-
Was meinst du mit "Verbindung trennen"? Trennt der andere PC die Verbindung oder schliesst du den Socket aus einem anderen Thread?
Und was für einen Fehlercode liefert select (bzw. genauer: was liefert WSAGetLastError() nachdem select SOCKET_ERROR zurückgegeben hat)?
-
hustbaer schrieb:
Was meinst du mit "Verbindung trennen"? Trennt der andere PC die Verbindung oder schliesst du den Socket aus einem anderen Thread?
Und was für einen Fehlercode liefert select (bzw. genauer: was liefert WSAGetLastError() nachdem select SOCKET_ERROR zurückgegeben hat)?
Hi,
ich starte meine Server-Anwendung und verbinde mich anschließend mit irgendeinem Programm zu diesem Server. Ich sende ein paar Dinge und alles klappt perfekt. Nun schließe ich das Clientprogramm. Mein Server erkennt das die Verbindung getrennt wurde, aber spuckt gleichzeitig einen Fehler bei
select()aus (Zeile 68). Der Fehlercode lautet:10038. Das entspricht wohlWSAENOTSOCK. Ich weiß aber nicht warum dieser Fehler auftritt und wie ich ihn beheben kann. Deswegen hier mal mein gesamter Code:#include <iostream> #include <sstream> #include <string> #include <windows.h> #include <winsock.h> const int MAX_CLIENTS = 10; const int PORT = 4321; long recvLine(SOCKET s, std::string& recv); long readLine(SOCKET s, std::stringstream& line); void error(const std::string& str); int startWinsock(); int main() { long rc; SOCKET acceptSocket; SOCKADDR_IN addr; FD_SET fdSet; SOCKET clients[MAX_CLIENTS]; if ((rc = startWinsock()) != 0) { error("startWinsock()"); } acceptSocket = socket(AF_INET, SOCK_STREAM, 0); if (acceptSocket == INVALID_SOCKET) { error("acceptSocket = socket()"); } memset(&addr, 0, sizeof(SOCKADDR_IN)); addr.sin_family = AF_INET; addr.sin_port = htons(PORT); addr.sin_addr.s_addr = INADDR_ANY; if ((rc = bind(acceptSocket, (SOCKADDR*)&addr, sizeof(SOCKADDR_IN))) == SOCKET_ERROR) { error("bind()"); } if ((rc = listen(acceptSocket, 10)) == SOCKET_ERROR) { error("listen()"); } for (int i = 0; i < MAX_CLIENTS; ++i) { clients[i] = INVALID_SOCKET; } while (true) { FD_ZERO(&fdSet); FD_SET(acceptSocket, &fdSet); for (int i = 0; i < MAX_CLIENTS; ++i) { if (clients[i] != INVALID_SOCKET) { FD_SET(clients[i], &fdSet); } } if ((rc = select(0, &fdSet, NULL, NULL, NULL)) == SOCKET_ERROR) { error("select()"); printf("WSA: %i\n", WSAGetLastError()); // Debug } if (FD_ISSET(acceptSocket, &fdSet)) { for (int i = 0; i < MAX_CLIENTS; ++i) { if (clients[i] == INVALID_SOCKET) { clients[i] = accept(acceptSocket, NULL, NULL); std::cout << "Neuer Client." << std::endl; break; } } } for (int i = 0; i < MAX_CLIENTS; ++i) { if (clients[i] == INVALID_SOCKET) { continue; } if (FD_ISSET(clients[i], &fdSet)) { std::string line; rc = recvLine(clients[i], line); if (!line.empty()) { std::cout << "Len: " << line << std::endl; rc = recvLine(clients[i], line); if (!line.empty()) { std::cout << "Other: " << line << std::endl; // - Data -// } } } } } } long recvLine(SOCKET s, std::string& recv) { std::stringstream buf; long rc = readLine(s, buf); if (rc == 0 || rc == SOCKET_ERROR) { closesocket(s); s = INVALID_SOCKET; std::cout << "Verbindung getrennt." << std::endl; } else { recv = buf.str(); } return rc; } long readLine(SOCKET s, std::stringstream& line) { long rc; for (char c; (rc = recv(s, &c, 1, 0)) > 0; line << c) { if (c == '\n') { return rc; } } return rc; } void error(const std::string& str) { std::cerr << "Error: " << str << std::endl; } int startWinsock() { WSADATA wsa; return WSAStartup(MAKEWORD(2, 0), &wsa); }Ich hoffe, ihr könnt mir nun besser helfen und habt vielleicht noch ein paar Anregungen zu meinem Code

-
Hi,
ich würd mal behaupten das liegt daran, dass du nur die lokale Kopie des Sockets in "recvLine" auf INVALID_SOCKET setzt und nicht in der main.
Gruß Pingu
-
Pingu-Group schrieb:
Hi,
ich würd mal behaupten das liegt daran, dass du nur die lokale Kopie des Sockets in "recvLine" auf INVALID_SOCKET setzt und nicht in der main.
Gruß Pingu
Ich übergebe nun Referenzen an die Funktionen und es klappt
Vielen Dank 
-
Hiho, wegen dem Problem des immer-rennenden-Servers.
Schau dir mal signal() an, damit könntest du deinen Server zum Beenden bringen, wenn der Benutzer es so will (SIGABRT -> STRG+C).
-
Hallo,
select + Blocking I/O macht keinen Sinn.
-
3 schrieb:
Hallo,
select + Blocking I/O macht keinen Sinn.
Da hast du jetzt auch wieder Recht
