Problem mit verkapselten Sockets
-
Ich bastele zur Zeit an einem kleinen Server (als Client benutze ich Telnet). Die angenommenen Verbindungen werden in einer std::list<Client> gespeichert, wobei ein Client den Socket und den Benutzernamen speichert und sich um das Schließen des Sockets kümmert. Den Socket, der Verbindungen annimmt, und die Clients werden über ein fd_set und select() verwaltet.
Wenn ich jetzt aber eine Verbindung herstelle, führt jeder Aufruf von select() zu einem WSAENOTSOCK (der über eine get-Methode aus dem Client geholte Socket macht also Probleme).Kann jemand sagen, woran das liegt / was ich anders machen muss? Eigentlich ist ein Socket unter Windows doch nur ein unsigned int, warum macht das dann diesen Fehler? Wenn ich die Clients einfach nur als Socket-Array speichere, dann funktioniert alles..
-
Ohne die relevanten Code-Ausschnitte bräuchte ich hellseherische Fähigkeiten.

-
Äh, klar.
Erstmal die Client-Klasse:
class Client { private: SOCKET m_sock; std::string m_ip; std::string m_name; public: Client(SOCKET accsock); // ruft vor allem accept() auf, und wirft bei dessen Fehlschlag eine Exception ~Client() { closesocket(m_sock); } SOCKET getSocket() { return m_sock; } };Und hier die relevanten Zeilen aus main():
int main() { WSockHandler ws; // Ruft im Konstruktor WSAStartup() auf, und im Destruktor WSACleanup() SOCKET accepts = socket(AF_INET, SOCK_STREAM, 0); SOCKADDR_IN addr; memset(&addr, 0, sizeof(SOCKADDR_IN)); addr.sin_port = htons(23); addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; bind(accepts, (SOCKADDR *)&addr, sizeof(SOCKADDR_IN)); listen(accepts, 10); timeval notime = {0,1}; std::list<Client> clients; fd_set set; while (!appdone()) { FD_ZERO(&set); FD_SET(accepts, &set); for (std::list<Client>::iterator it = clients.begin(); it != clients.end(); ++it) { SOCKET s = it->getSocket(); if (s != INVALID_SOCKET) FD_SET(s, &set); } if (select(0, &set, 0, 0, ¬ime) == SOCKET_ERROR) { std::cout << timestamp() << "Error: Error while select()ing! Error code: " << WSAGetLastError() << '\n'; continue; } if (FD_ISSET(accepts, &set)) { try { clients.push_back(accepts); } catch (accept_failed) {} } /* Hier ist dann noch die restliche Abfrage des FD_SETs */ } }Die Überprüfungen der Socketfuntionen habe ich rausgenommen, die laufen aber einwandfrei.
Das Problem ist wie gesagt der select()-Aufruf, sobald ich eine Verbindung aufbaue gibt es Fehlercodes zurück.
-
ich finde eine microsekunde ein bisschen kurz zum selecten

übergib mal statt ¬ime NULL (zum testen)
-
Ändert auch nichts. Eine Mikrosekunde habe ich aber auch schon in einem anderen Programm verwendet, da lief das problemlos..
-
Also erstmal folgendes:
The parameter time-out controls how long the select can take to complete. If time-out is a null pointer, select will block indefinitely until at least one descriptor meets the specified criteria. Otherwise, time-out points to a TIMEVAL structure that specifies the maximum time that select should wait before returning. When select returns, the contents of the TIMEVAL structure are not altered. If TIMEVAL is initialized to {0, 0}, select will return immediately; this is used to poll the state of the selected sockets.
timeval notime = {0,0};
wäre also einfach bezeichnender ( nicht besser oder richtiger ).
Ansonsten sieht soweit alles ok aus, deshalb würde ich vorschlagen, dass du mal den client-constructor postest.
-
Kannst du haben, macht aber nicht viel mehr als in dem Kommentar stand:
Client::Client(SOCKET accsock) { SOCKADDR_IN saddr; int len = sizeof(SOCKADDR_IN); m_sock = accept(accsock, (SOCKADDR *) &saddr, &len); if (m_sock == INVALID_SOCKET) throw accept_failed("Accept failed."); m_ip = inet_ntoa(saddr.sin_addr); // Loggen, Begrüßung senden }Und mit einem {0,0}-timeval war mir mal irgendwas komisches passiert, weiß nicht mehr was.
-
Lideric schrieb:
[...]
if (FD_ISSET(accepts, &set)) { try { clients.push_back(accepts); } catch (accept_failed) {} } /* Hier ist dann noch die restliche Abfrage des FD_SETs */ } }[...]
Ähmmm... Sieht irgendwie aus, als würde da ein Client-Objekt auf dem Stack erstellt ( clients.push_back(accepts) ), in dessen Constructor dann auch brav das accept erfolgt und m_sock auch brav initialisiert wird... dies wird dann an die Liste angehangen (kopiert), aber leider danach auch wieder zerstört ( closesocket() ). Damit ist die Socket dann geschlossen und das Client-Objekt in der Liste hat einen ungültigen Socket-Descriptor. Denk ich mir mal so.
-
Oh, verdammt, tatsächlich. Dann muss ich wohl ein Bisschen was am Design ändern. ..
Aber auf jeden Fall vielen Dank!