WinSocks beim start starten...



  • Hi,

    ehm ich bastel grade an sonem "Multi-Chat" in WinApi mit WinSocks und stoße schon auf erste Hürden^^ rofl...

    http://www.imagespell.com/show.php?id=2e4fe38a1f55eef12ce6423db95c17fc.jpg

    Doch wie mache ich es, dass die WinSocks beim start (nachdem das Fenster erstellt würde) ausgeführt werden?? Also von WSAStartup bis accept() ??
    In dem Screen^^ habe ich es von WSAStartup bis zum listenModus geschafft^^, weil ich die Funktionen in der WM_CREATE Message ausgeführt habe.
    Aber sobald ich accept() auch noch in die WM_CrATE Message packe öffnet sich nichtmal das Fenster ^^ -.-

    Habt ihr da eine idee??



  • afaik ist accept ein blocking command. D.h. dass das Programm an der Stelle wartet, bis eine Verbindung angenommen wird. Wenn der Befehl in WM_CREATE steht, wird das Fenster eben nicht angezeigt.
    So kann man die Sockets non-blocken:

    u_long arg = 1;
    ioctlsocket(acceptSocket, FIONBIO, &arg);

    Dann musst du natürlich bei jedem Durchlauf der Programmprozedur den Socket prüfen.



  • Extinction schrieb:

    afaik ist accept ein blocking command. D.h. dass das Programm an der Stelle wartet, bis eine Verbindung angenommen wird. Wenn der Befehl in WM_CREATE steht, wird das Fenster eben nicht angezeigt.
    So kann man die Sockets non-blocken:

    u_long arg = 1;
    ioctlsocket(acceptSocket, FIONBIO, &arg);

    Dann musst du natürlich bei jedem Durchlauf der Programmprozedur den Socket prüfen.

    Hmm ich habe jetzt noch select() dazugepackt um mehrere server connecten zu lassen... Wie soll ich die Funktion jetzt da einsetzten???



  • Sooo

    ich habe jetzt ein bischen (was heißt ein bisschen ... SEHR VIEL) rumrecherchiert:

    Also select() ist zwar gut^^ aba WSAAsyncSelect() ist besser xD
    Zumindest für WinApi Anwendungen^^ (hab ich i-wo gelesen^^)

    Jedoch habe ich nicht so richtig verstanden was WSAAsyncSelect eigentlich macht???

    The Windows Sockets WSAAsyncSelect function requests Windows message-based notification of network events for a socket.

    Heißt das jetzt, dass die Funktion WSAAsyncSelect WinSocks erlaubt wie Windows-Messages (zB. WM_PAINT, WM_COMMAND usw..) auf Verbindungen von außen zu reagieren???
    **
    Wie ich mir das Vorstelle:**
    Ein Server besitzt einen Socket: "AcceptSocket"
    "AcceptSocket" ist an einen Port gebunden und im Listen-Modus...
    Dann wird "AcceptSocket" in WSAAsyncSelect() reingepackt:

    WSAAsyncSelect(AcceptSocket, hWnd, WM_SOCKET, FD_ACCEPT | FD_WRITE | FD_READ | FD_CLOSE);
    

    Sobald dann ein Client versucht auf den server zu connecten o.ä, sendet Windows die passende Message: FD_READ, FD_CLOSE, FD_CONNECT usw^^

    Ich weiß jetzt nicht was die message auf: "Eingehende verbindung von Außen" ist, deswegen sag ich jetzt einfach mal das ist die "FD_CONNECT" Message^^ Wenn dann halt sone message ankommt kann man in "FD_CONNECT" die accept() Funktion einmal (!) ausführen, sodass nixx blockiert wird^^
    Dann gibt accept einen socket zurück usw....
    So in der Art läuft das auch mit den aderen Blocking Calls recv(), send() usw...

    Ist das so richtig??
    Oda bin ich auf dem völlig falschen pfad???



  • WSAAsyncSelect setzt den Socket in den Non-Blocking Modus so das recv, send etc. keine blocking calls mehr sind.^^



  • Wenn du auf den Listening-Socket WSAAsyncSelect() aufgerufen hast, bekommst du ein FD_ACCEPT sobald ein Client sich mit deinem Server verbinden will.
    Daraufhin solltest du dann accept() aufrufen.



  • OK ok das hab ich jetzt auch verstanden (juhu!!)

    Jetzt habe ich aber wieder ein neues Problem:

    Ich mache ja für den Chat so eine Server-Liste (Siehe Bild oben^^), dh. da werden alle Server aufgelistet sein die eine Verbindung zu mir aufnehmen wollen.
    Aber wie finde ich Info's wie den Namen, den der chat-partner beim server angegeben hat heraus??? Unzwar muss das ja noch vor accept() sein, weil wenn mehrere Server zu mir connecten wollen kann ich mich ja schlecht mit jedem verbinden^^, da müsste ich ja ziemlich viele Sockets erstellen^^

    Kann der Server, noch bevor er sich mit dem Clienten verbindet, einige Info's schicken, damit man auch den Namen in der Liste sehen kann???

    Protokoll ist TCP



  • nein - ohne Verbindung kannst du nix übertragen, sonst wäre die Verbindung ja unnötig (bei TCP) 😉

    Abgesehen davon verbindet sich kein Server mit einem Client sondern andersherum, sonst wäre der Server kein Server.
    Der Server kann die Verbindung vom Client nur annehmen oder eben nicht.
    (Es sei denn das Server-Programm enthält sowohl eine Client- als auch Server-Komponente)

    Wenn du weniger Verbindungen haben willst, nimm doch ein verbindungsloses Protokoll wie UDP (welches aber auch wieder seine Nachteile hat).



  • geeky schrieb:

    nein - ohne Verbindung kannst du nix übertragen, sonst wäre die Verbindung ja unnötig (bei TCP) 😉

    Abgesehen davon verbindet sich kein Server mit einem Client sondern andersherum, sonst wäre der Server kein Server.
    Der Server kann die Verbindung vom Client nur annehmen oder eben nicht.
    (Es sei denn das Server-Programm enthält sowohl eine Client- als auch Server-Komponente)

    Wenn du weniger Verbindungen haben willst, nimm doch ein verbindungsloses Protokoll wie UDP (welches aber auch wieder seine Nachteile hat).

    Heißt das wenn ich so eine liste machen will muss ich jede einzelne verbindung einmal akzeptieren um info's in die liste zu schreiben? (OMG das wird ne komplizierte Funktion... -.- rofl...)

    Aber die ip muss man ja herausfinden können bevor man accept()et, oder?
    Wie mache ich das?



  • accept() liefert bei Verbindungsannahme optional die IP mit.
    Ansonsten gibt es noch getpeername, was aber auch nur mit einem verbundenen Socket funktioniert.



  • Nagut diese frage da hat sich geklärt^^
    Ich denk mal das besste ist, wenn ich 2 ports benutze^^

    habe jetzt aber eine andere:
    Wie kann ich mit connect() in regelmäßigen zeitabständen prüfen ob der server da ist, ohne zu blockieren?
    Ich habe es mit einer Schleife und sleep probiert, doch da wird logischer Weise bockiert -.-

    Kennt jemand eine bessere Lösung??



  • Nimm wieder WSAAsyncSelect() (vor Aufruf von connect() ) und du bekommst eine FD_CONNECT Nachricht wenn es geklappt hat.

    Die meisten Anwendungen scheinen allerdings für sowas einfach nen Thread zu starten und da drin mit blockierenden Sockets zu arbeiten.



  • geeky schrieb:

    Nimm wieder WSAAsyncSelect() (vor Aufruf von connect() ) und du bekommst eine FD_CONNECT Nachricht wenn es geklappt hat.

    Die meisten Anwendungen scheinen allerdings für sowas einfach nen Thread zu starten und da drin mit blockierenden Sockets zu arbeiten.

    Das dumme ist nur, das ich immer (!) eine FD_CONNECT message bekomme^^, selbst wenn nix verbunden ist^^

    Hier der komplette Source vom Clienten:
    http://nopaste.com/p/avSrghNvD
    http://nopaste.com/p/aNzR5ZIV6
    http://nopaste.com/p/aIcIu57rN



  • Habe jetzt einen neuen thread für Connect angelegt, weil man mit FD_CONNECT anscheinend nixx anfangen kann -.-

    Funktioniert auch ganz gut aba irgendwas habe ich in der Schleife falsch gemacht und finde den Fehler einfach nicht:

    DWORD WINAPI ThreadFunktion(LPVOID param)
    {
    	while(test2 == SOCKET_ERROR)
    	{
    		test2 = connect(s, (SOCKADDR*)&addr, sizeof(SOCKADDR_IN));
    		if(test2 == SOCKET_ERROR)
    		{
    			AddText("Fehler: Connection gescheitert!");
    			Sleep(1000);
    		}
    		else
    		{
    			AddText("Verbunden mit 127.0.0.1 .!");
    			return 1;
    		}
    	}
    	return 0;
    }
    

    Also wenn man den Server zuerst an macht und danach den Clienten, dann funktioniert auch alles richtig. Also er sagt:
    "Verbunden mit 127.0.0.1 .!"

    Aber wenn ich zuerst den Clienten an mache und danach den Server, dann sagt er immer: "Fehler: Connection gescheitert!"
    Doch der Server sagt das eine Verbindung akzeptiert wurde und der Client hat sogar "Hallo" geschickt, obwohl der Client die ganze zeit "Fehler: Connection gescheitert!" ausgibt -.-

    Also irgendwie ist das komisch.... Liegt es evtl daran das die variable "test2" global ist??? Aber local kann ich da keine Variale anlegen....



  • Wieso solltest du in einer Thread-Funktion keine lokale Variable anlegen können?
    Kann es sein, dass test2 auch noch irgendwo außerhalb des Threads bearbeitet wird?

    Rob'



  • Werte den Fehler mal näher aus: WSAGetLastError()

    In deiner WM_SOCKET: Werte noch WSAGETSELECTERROR() aus.
    Eventuell kriegste bei FD_CONNECT auch noch was zu dem merkwürdigen Verhalten über den Socket (steht in wParam) raus, für den da Windows dir ein FD_CONNECT verschaukelt 😉

    (Variablen/Objekte die du in mehreren Threads benutzt solltest du synchronisieren)



  • Sooo..... Habe Problem gelöst(Aber habe wieder ein weiteres Problem, siehe unten):

    Wenn ich zuerst WSAAsyncSelect() aufgerufen habe und danach connect(), dann sendet er IMMER eine FD_CONNECT Message.
    ABER wenn ein Fehler beim Verbinden aufgetreten ist, dann füllt er den WORD: wError = WSAGETSELECTERROR(lParam); mit dem error.

    Und dann kann man das ganz einfach mit einer if Anweiung checken:

    case FD_CONNECT:
    
    							if (wError)
    							   {
    									AddText("Warte auf Verbindung");
    									connect(s, (SOCKADDR*)&addr, sizeof(SOCKADDR_IN));
    									return TRUE ;
    							   }
    
    							    AddText("Verbunden mit 127.0.0.1 .!");
    							    return 0;
    

    Ohne das ich irgendwelche threads oder Schleifen brauche, weil FD_CONNECT ja immer aufgerufen wird sobald man die Funktion connect() ausgeführt hat^^

    Jedoch bin ich mir nicht ganz Sicher was das angeht weil bei FD_CLOSE klappt das dummerweise nicht -.-

    case FD_CLOSE:
    							AddText("Verbindung abgebrochen!");
    							connect(s, (SOCKADDR*)&addr, sizeof(SOCKADDR_IN));
    

    Weil Wenn Client und Server miteinander verbunden sind und der Server plötzlich off geht, dann muss der Client ja weiter prüfen ob eine Verbindung besteht , falls der Server wieder online geht
    Aber wenn ich in der message connect() ausführe, dann wird komischerweise keine FD_CONNECT Nachricht geschickt
    Weiß vllt einer woran das liegen kann???



  • Ich habe jetzt mal die Rückgabewerte mit WSAGetLastError() gecheckt:

    naja als erstes gabs den Fehler:

    Socket is already connected.

    Dann habe ich closesocket(s) aufgerufen, danach hatte ich gleich nen Weiteren Fehler:

    Socket operation on nonsocket.

    Dann habe ich Socket s nochmal neu erstellt und jetzt kriege ich die richtige fehlermeldung:

    Connection refused.

    ABER FD_CONNECT WIRD TRODSTEM NICHT GESENDET!!!!
    MAN langsam werde ich hier.....

    Ka was ich jetzt machen soll.... hat vllt jemand eine Idee??



  • Ok habe den Fehler grade selber gefunden:

    Weil ich den Socket s in FD_CLOSE geschlossen habe und ihn danach neu erstellt habe, musste ich auch

    WSAAsyncSelect(s, hWnd, WM_SOCKET, FD_CONNECT | FD_WRITE | FD_READ | FD_CLOSE);
    

    nochmal aufrufen^^


Anmelden zum Antworten