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
bekommeBeide 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überUmgedreht 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 nichtIch 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 werdenNicky