Winsocks Socket Disconnect



  • Weil synchrone Sockets kaum geeignet sind für mehr als 10 Verbindungen, hab ich mir Asynchrone Sockets mal angeschaut wo man einfach von Windows benachrichtigt wird wenn z.B. von einem Socket gelesen werden kann. Ich hab erstmal versucht Wrapper Klassen für Client und Server zu erstellen, ob das überhaupt Sinn macht oder überflüssig ist ist noch fraglich.
    Auf jeden fall funktioniert es soweit ganz gut, ich hab nur Probleme mit Sockets die die Verbindung trennen. Ich hab ein Fenster mit entsprchender WindowProc, bei WM_CREATE wird ganz normal erstmal das startup Zeug für Winsocksgemacht und WSAAsyncSelect:

    server.WSAAsyncSelect(hWnd, SOCKET_EVENT, FD_READ | FD_ACCEPT | FD_WRITE | FD_CONNECT | FD_CLOSE)
    

    Ich glaub mal dass nichtmal alle dieser FD Nachrichten benötigt werden. Zum Beispiel wüsste ich nicht wieso man FD_WRITE überhaupt braucht, soweit ich weis kann immer was an einen Socket gesendet werden und es wird nichts blockiert.

    Das eigentliche Problem ist aber FD_CLOSE. Ich dachte ja erstmal dass wenn ein Client die Verbindung trennt da einfach eine FD_READ Nachricht kommt und 0 bytes gelesen werden, wodurch man weis dass dieser Client entfernt werden kann.
    Aber stattdessen ist diese Bedingung erfüllt:

    if ( err=WSAGETSELECTERROR ( lParam ) )
    

    Der Fehlercode ist 10053:Software caused connection abort.

    Soweit erstmal nicht schlimm, auch ne Möglichkeit über Verbindungsabbruch benachrichtigt zu werden. Aber ich kann das doch gar nicht zu einem Socket zuordnen. Wenn ich 10 Sockets hab und einer trennt die Verbindung, sehe ich keine Möglichkeit rausuzufinden welcher das war. Ich dachte ich könnte select benutzen:

    readfds:

    · If listening, a connection is pending, accept will succeed
    · Data is available for reading (includes OOB data if SO_OOBINLINE is enabled)
    · Connection has been closed/reset/terminated

    aber dann werden doch auch sockets selektiert die keinen disconnect haben sondern einfach nur gelesen werden können, wie bei FD_READ.

    Also kann mir einer sagen wie man rausfinden soll dass bei einem Socket die Verbindung getrennt wurde und auch rausfinden bei welchem Socket?



  • Hallo,

    mach dir doch mal die Mühe und lasse dir zu jedem Ereignis ein Meldungsfenster
    mit einem Text ("FD_WRITE wurde aufgerufen", "FD_CLOSE wurde aufgerufen" usw) anzeigen.
    Dann weißt du wann welche Nachricht gesendet wird.

    Soweit ich mich erinnere wird FD_WRITE nur beim Serversocket aufgerufen und zwar wenn ein Client verbunden wurde.
    Im Parameter wParam oder lParam (weiß nicht genau welcher von beiden) wird dabei das Sockethandle übergeben, somit weißt du wer verbunden ist.

    Ebenso wirst du bei FD_CLOSE informiert. In einem der Parameter steht das jeweilige Sockethandle.
    Das gleichst du mit allen verbundenen Sockets in deiner Liste ab und schon weißt du welches getrennt wurde.

    WSAAsyncSelect() wendest du auch nur auf das Socket (beim Server) an, welches du über Accept() zurückbekommen hast,
    nicht auf das was du selbst erstellt hast!

    Gruß, Nicky



  • Since an accept'ed socket has the same properties as the listening socket used to accept it, any WSAAsyncSelect events set for the listening socket apply to the accepted socket.

    man ruft WSAAsyncSelect nur für den serversocket auf...

    und dass der Socket in wParam oder lParam ist, davon hab ich noch nie gelesen. Wozu braucht man dann select um lesbare Sockets rauszufinden? Ich hatte jetzt voll aufwändig extra ein fd_set womit dann über select die sockets ausgewählt wurden. Im Turoail stand

    You can pass a set of sockets to the select() function to see which ones are ready for reading, writing, or have returned errors.

    Und ich hab mir die Mühe gemacht bei jedem Ereignis was ausgeben zu lassen, zu FD_CLOSE kommt es jedenfalls nie wenn ein Socket die Verbindung getrennt hat. Ich könnte vieleicht was an den Client senden und prüfen ob das ging, ich weis nicht ob das immer die beste Lösung wär.



  • Nikolai schrieb:

    man ruft WSAAsyncSelect nur für den serversocket auf...

    Nicht unbedingt:
    The socket created by the accept function has the same properties as the listening socket used to accept it. Consequently, WSAAsyncSelect events set for the listening socket also apply to the accepted socket. For example, if a listening socket has WSAAsyncSelect events FD_ACCEPT, FD_READ, and FD_WRITE, then any socket accepted on that listening socket will also have FD_ACCEPT, FD_READ, and FD_WRITE events with the same wMsg value used for messages. If a different wMsg or events are desired, the application should call WSAAsyncSelect, passing the accepted socket and the desired new data.

    supernicky2 schrieb:

    In einem der Parameter steht das jeweilige Sockethandle.

    So ist es:
    The wParam parameter identifies the socket on which a network event has occurred.

    Die englischen Zitate sind aus:
    http://msdn.microsoft.com/en-us/library/windows/desktop/ms741540(v=vs.85).aspx



  • Nikolai schrieb:

    Since an accept'ed socket has the same properties as the listening socket used to accept it, any WSAAsyncSelect events set for the listening socket apply to the accepted socket.

    man ruft WSAAsyncSelect nur für den serversocket auf...

    und dass der Socket in wParam oder lParam ist, davon hab ich noch nie gelesen. Wozu braucht man dann select um lesbare Sockets rauszufinden? Ich hatte jetzt voll aufwändig extra ein fd_set womit dann über select die sockets ausgewählt wurden. Im Turoail stand

    You can pass a set of sockets to the select() function to see which ones are ready for reading, writing, or have returned errors.

    Und ich hab mir die Mühe gemacht bei jedem Ereignis was ausgeben zu lassen, zu FD_CLOSE kommt es jedenfalls nie wenn ein Socket die Verbindung getrennt hat. Ich könnte vieleicht was an den Client senden und prüfen ob das ging, ich weis nicht ob das immer die beste Lösung wär.

    Hallo,

    rufe WSAAsyncSelect() für das Socket auf was du zurückbekommst von Accept(),
    dann erhälst du alle Nachrichten.

    Google: http://msdn.microsoft.com/en-us/library/windows/desktop/ms737526%28v=vs.85%29.aspx

    Select() ermittelt den Status eines Sockets aber benachrichigt dich nicht.
    Schreibe doch mal deinen Code wie bei dir ein Socket erstellt wird, ein Socket wartet
    und wie eine Verbindung angenommen wird.

    Daten zu senden um zu schauen ob noch jemand da ist bringt nichts... Dafür sind
    diese Nachrichten ja gemacht und sie funktionieren sehr gut.

    Schau auch mal in die MSDN.

    Nicky


Log in to reply