Gelöscht



  • Du solltest dir sowieso überlegen welches IO Modell du verwendest.

    select() mit blocking Sockets ist IMO problematisch, weil es theoretisch sein kann dass man von select geweckt wird, der recv/send/accept Call aber dann trotzdem blockiert -- und dann u.U. sehr lange blockiert. Und dann steht der Server, was garnicht gut ist.

    Blocking IO ist IMO nur mit Threads wirklich zu gebrauchen.

    Das "reactive IO" Modell (auch als "asynchronous IO" bekannt) verwendet select() mit non-blocking Sockets. Funktioniert grundsätzlich recht gut, boss für wirklich gute Performance, speziell auf Multi-Core Maschinen nicht optimal.

    Das "proactive IO" Modell verwendet z.B. IO Completion Ports. Skaliert sehr gut, und lässt sich auch sehr einfach mit Thread-Pools kombinieren.

    Wenn du dich für ein bestimmtes Modell entschieden hast sollte dann auch klar sein wie du das mit Verbindungen annehmen hinbekommst ohne den Server zu blockieren, oder wie du mitbekommst wenn ein Client sich getrennt hat.

    Dazu noch ein Hinweis: theoretisch reicht es wenn der Server in einem recv() wartet dass vom Client was kommt. Wenn dieser die Verbindung "aktiv trennt", dann kommt recv() mit 0 zurück (bzw. wird die Completion-Routine mit entsprechenden Parametern aufgerufen). Blöd ist nur wenn der Client einfach "wegstirbt", d.h. wenn vom Client kein "RST" Paket geschickt wird, der aber trotzdem einfach "weg" ist. In dem Fall kann es *sehr* lange dauern bis der dein Server-Programm die Info bekommt "Client ist futsch". Um solche Fälle schneller mitzubekommen ist es gut wenn man in periodischen Abständen "Dummy Pakete" zwischen Client und Server hin und herschickt. Wenn definiert ist dass jede Minute so ein Paket geschickt werden muss, und der Server hört z.B. 10 Minuten von einem Client nichts mehr, dann kann er die Verbindung einfach trennen. Bzw. wird der Server schneller vom TCP/IP Stack auch viel schneller die Info bekommen dass der Client weg ist, wenn der Server versucht selbst so ein Paket zu senden.
    Von daher ist es günstig solche Dummy-Pakete zu senden, wenn man die Möglichkeit dazu hat (d.h. wenn es das Protokoll welches man verwendet ermöglicht, bzw. man das Protokoll selbst definieren kann).



  • Das "reactive IO" Modell (auch als "asynchronous IO" bekannt)

    Falsch



  • flasch schrieb:

    Das "reactive IO" Modell (auch als "asynchronous IO" bekannt)

    Falsch

    Genaugenommen falsch, von mir aus.

    Wenn allerdings irgendwo bloss "asynchronous IO" steht, ohne weitere Angaben, und es um Sockets geht, dann ist normalerweise das reaktive Modell gemeint. Genauer: select().



  • The Reactor patterns involve synchronous I/O, whereas the Proactor pattern involves asynchronous I/O

    http://www.artima.com/articles/io_design_patterns2.html

    http://en.wikipedia.org/wiki/Reactor_pattern



  • Irgendwas zu zitieren ändert nichts daran dass der Begriff in der Art verwendet wird, wie er nunmal verwendet wird.

    Siehe auch http://en.wikipedia.org/wiki/Asynchronous_I/O - wenn du aufpasst wird dir vielleicht auffallen dass dort explizit select() erwähnt wird. select() mit non-blocking Sockets ist nunmal asynchron.

    EDIT: oder auch hier: http://www.ibm.com/developerworks/linux/library/l-async/index.html
    Absatz "Asynchronous blocking I/O"



  • sk0r schrieb:

    Hallo,

    wie kann ich per WinSocks als Server überprüfen,
    ob ein Client nicht mehr verbunden ist? Ich habe nämlich
    eine struct, welche Events bereitstellt, u.a. auch OnDisconnect.
    Wie kann ich nun überprüfen, ob ein Client nicht mehr mit dem
    Server verbunden ist, wegen welchem Grund auch immer?!

    MfG: sk0r

    Hi,

    verwende WSAEventSelect() oder WSAAsyncSelect() (wenn Du eine GUI hast) so kannst Du auf das FD_CLOSE - Event oder FD_CLOSE - Nachricht warten lassen, ohne Schleife.

    Ein (noch unfertiges) Beispiel eines Client-Threads mit WSAEventSelect(), hier werden: FD_READ und FD_CLOSE ausgewertet:

    DWORD WINAPI MOSVR_ClientThread(SOCKET hClient){
    	SOCKET mySock = hClient;
    	static char *si = MOSVR_GetResString(300);
    
    	::send(mySock, si, strlen(si), 0);
    
    	WSAEVENT wEvent = ::WSACreateEvent();
    	if(wEvent == WSA_INVALID_EVENT) return 1;
    	if(::WSAEventSelect(mySock, wEvent, FD_CLOSE | FD_READ) == SOCKET_ERROR) return 1;
    	WSAEVENT wEar[1] = { wEvent };
    	WSANETWORKEVENTS wE;
    
    	for(;;){
    		ZeroMemory(&wE, sizeof(wE));
    
    		DWORD dwrVal = ::WSAWaitForMultipleEvents(1, wEar, false, WSA_INFINITE, false);
    		if(dwrVal == WSA_WAIT_FAILED) break;
            if(::WSAEnumNetworkEvents(mySock, wEar[0], &wE) != SOCKET_ERROR){
    			switch(wE.lNetworkEvents){
    				case FD_READ:
    					MOSVR_ReadClientCommands(mySock);
    					break;
    				case FD_CLOSE:
    					::WSACloseEvent(wEvent);
    					::closesocket(mySock);
    					return 0;
    			}
    		}
    		::WSAResetEvent(wEar[0]);
    	}
    
    	::WSAEventSelect(mySock, wEvent, 0);
    	::WSACloseEvent(wEvent);
    	::closesocket(mySock);
    	return 0;
    }
    

    Der Client läuft in einem Service, hier ist eine GUI nicht möglich.



  • ...



  • Der "beliebteste" Fehler beim Thema Socket-Programmierung, ist, dass Leute glauben "recv" würde "Pakete" empfangen, so wie sie mit "send" abgeschickt werden. Das ist nicht so. Es gibt bei Stream-Sockets keine "Paketgrenzen" oder "Nachrichtengrenzen". Wenn du 2x send mit je 100 Byte machst, kann es sein, dass ein einziges recv die ganzen 200 Byte empfängt. Oder auch nur 150 byte, oder gar nur 1 Byte.

    Was mich gleich zum zweit-beliebtesten Fehler bringt: manche Leute nehmen an dass recv genau so viel Byte empfängt wie man "verlangt". Das ist auch nicht so. recv empfängt von 1 bis N Byte, bzw. bei nonblocking Sockets von 0 bis N Byte.

    Lies die Doku, sehr genau, steht alles drin was man wissen muss 😉



  • ...



  • http://msdn.microsoft.com/en-us/library/ms740121(VS.85).aspx
    die Doku ist teilweise auch auf Deutsch verfügbar, recv() gehört aber glaube ich nicht dazu...



  • ...


Anmelden zum Antworten