GELÖST: Socketprogrammierung WinApi -- Nachricht FD_READ wird nicht aufgerufen



  • Hallo zusammen,

    Nach dem Unix-Thread nun einer für Windows 💡

    Ich habe ein Spiel geschrieben das ich nun zwecks Mehrspieler netzwerk-
    tauglich machen will.

    Da das Programm mit MASM erstellt ist erspare ich euch mal die vielen Zeilen
    Code und versuche es so gut es geht zu erklären was ich will und was ich
    bekomme ⚠

    Beide Programme sind im Prizip gleich aufgebaut.
    Beim Client und Server werden folgende Schritte gleich ausgeführt:

    invoke WSAStartup, ebx, addr wsadata
    	mov eax, offset wsadata.szDescription
    
    	invoke socket, AF_INET, SOCK_STREAM, IPPROTO_TCP	;socket erstellen und in mysock speichern
    	mov mysock, eax
    
    invoke WSAAsyncSelect, mysock, hWnd, WM_SOCKET_NOTIFY, FD_CONNECT or FD_READ or FD_CLOSE or FD_ACCEPT
    
    invoke gethostbyname, addr dnsname
    

    WSAStartup wird aufgerufen
    Socket erstellen
    WSAAsyncSelect aufrufen um über den Status des Sockets benachrichtigt zu werden.

    Beim Client wird nun folgendes ausgeführt:

    invoke connect, mysock, addr sa_in, sizeof sa_in
    

    Beim Server dieses:

    invoke bind, mysock, addr sa_in, sizeof sa_in
    	invoke listen, mysock, 1
    
    	nochmal1:
    				invoke accept, mysock,addr server_in, addr gr_sa_server
    				mov serversock, eax
    				cmp serversock, 0d
    				je nochmal1
    

    Accept() wird in einer Schleife aufgerufen bis eine Verbindung steht.
    Durch WSAAsyncSelect wird mein Programm dadurch nicht blockiert.

    Hier noch der Auszug aus der WndProc von beiden:

    WndProc proc hWin   :DWORD,
                 uMsg   :DWORD,
                 wParam :DWORD,
                 lParam :DWORD
    
            mov edi, uMsg		
            .elseif edi == WM_SOCKET_NOTIFY
            	mov edx, lParam
    
    		;push edx
    			.if dx == FD_CONNECT
    
    				invoke MessageBox, NULL,addr txtconnect, addr szCaption, MB_OK
    
    			.endif
    
    			mov edx, lParam
    			.if dx == FD_CLOSE
    
    				invoke MessageBox, NULL,addr txtclose, addr szCaption, MB_OK
    
    			.endif
    
    			mov edx, lParam
    			.if dx == FD_READ
    
    				invoke MessageBox, NULL, addr txtread, addr szCaption, MB_OK
    
    			.endif
    
    			mov edx, lParam
    			.if dx == FD_ACCEPT
    
    				invoke MessageBox, NULL, addr txtaccept, addr szCaption, MB_OK
    
    			.endif
    
            ret
    

    Zum Beenden habe ich für den Client folgendes:

    sock_end proc
    
    	invoke closesocket, mysock
    	invoke CloseHandle, mysock
    	xor eax, eax
    	mov mysock, eax
    
    	invoke WSACleanup
    
    	invoke SendMessage, hWnd, WM_SOCKET_NOTIFY,0 , FD_CLOSE
    
    	Ret
    sock_end EndP
    

    Für den Server dies:

    sock_end proc
    
    	invoke closesocket, serversock
    	invoke CloseHandle, serversock
    	invoke closesocket, mysock
    	invoke CloseHandle, mysock
    	xor eax, eax
    	mov serversock, eax
    	mov mysock, eax
    
    	invoke WSACleanup
    
    	invoke SendMessage, hWnd, WM_SOCKET_NOTIFY,0 , FD_CLOSE
    
    	Ret
    sock_end EndP
    

    Nun meine Fragen:

    Über die Nachrichten FD_CONNECT, FD_ACCEPT werde ich bei beiden Informiert
    mit einer MessagBox().
    FD_CLOSE wird nur benachrichtigt wenn ich beim Server die Verbindung (sock_end)
    abbreche. Dann erhalte ich beim Client eine Mitteilung darüber 👍

    Umgedreht jedoch nicht. Der Server "glaubt" dann noch er sei verbunden.
    Kann es was mit der Reihenfolge von closesocket und CloseHandle zu tun haben? 💡

    Worüber ich bei beiden nicht benachrichtigt werde ich FD_READ.
    Ich habe in den Programmen einen Button der einen Text sendet (send()) und ein
    anderer ruft ihn ab (recv()).

    SENDEN:

    .elseif uMsg == WM_COMMAND	
    
    		mov edx, lParam
    		.if edx==hwnd_button1				
    			invoke send, mysock, addr txtsenddata, 30,0
    
    		.endif
    

    EMPFANGEN:

    .elseif uMsg == WM_COMMAND	
    
    		mov edx, lParam
    		.if edx==hwnd_button2				
    			invoke recv, serversock, addr tcpbuffer, 30,0	
    			invoke MessageBox, NULL,addr tcpbuffer, addr szCaption, MB_OK
    		.endif
    

    Daß das senden funktioniert habe ich mit einem anderen Programm getestet.
    Nur hier kommt nichts an... bei beiden nicht 😞

    Ich hoffe jemand hat einen Rat für mich... sitze schon etwas länger vor diesem
    Problem und gebe eingentlich nicht so schnell auf. Falls noch Code fehlt, bitte
    kurz bescheid geben... ich ergänze ihn dann.

    Danke und Gruß

    Nicky



  • Du es sich hierbei um Assembler handelt, kann ich dir nur eingeschränkt helfen.

    Mal ein paar Hinweise:
    recv und send müssen nicht zwangsläufig die Anzahl an Bytes empfangen oder senden, die du angegeben hast.

    Es kann also sein, dass du die Funktionen mehrfach aufrufen musst bis alle Daten gelesen oder geschrieben sind.

    Ein Verbindungsabbruch kann nur dann erkannt werden, wenn die Verbindung korrekt (also mit closesocket - was das CloseHandle da soll ist mir schleierhaft!) beendet wurde. Bei einem ungewollten Verbindungsabbruch (Stromfall, Atombombenangriff, ...) geriert man in einen Dead-Lock. Die Funktion wird nie mehr zurückkehren und wird nie erfahren, dass die Verbindung tot ist.

    Na ja, mehr kann ich dir leider nicht dazu sagen, da ich Assembler nicht kann.



  • Hallo seltsamer Name,

    Ich habe extra nur den Teil mit den Api-Funktionen kopiert 😉

    Den Text sende ich mit jedem Knopfdruck neu. Wie schon geschrieben funktioniert
    das Senden mit einer anderen Anwendung tadellos.
    Dort habe ich genau die selben Api-Aufrufe.

    Wenn ich die Server-Anwendung einfach schließe (Kreuz rechts oben) wird der
    Client darüber informiert mit einer Nachricht, umgekehrt jedoch gar nicht.

    Ich schmeiße CloseHandle() mal raus und warte auf weitere Tipps und Anregungen.

    Danke erstmal

    Nicky

    PS: wenn ich WSAAsyncSelect nicht aufrufe für das Socket kann ich Daten senden
    und empfangen.
    Wenn ich mit Accept() in der Serveranwendung ein neues Socket erstellt habe,
    muss ich auf dieses nochmals WSAAsyncSelect anwenden?



  • Hallo zusammen,

    mit der Frage meines letzten Beitrags hat sich mein Problem gelöst!

    Wenn das neue Socket mit Accept() erstellt wird, muss darauf (und nur dort)
    ein WSAAsyncSelect() ausgeführt werden 👍

    Nicky


Anmelden zum Antworten