Server Lösung bricht unerwartet ab
-
Hallo Leute!
Ich habe mir einen kleinen Server gebastelt und warte auf den Accept Event, den ich vorher mit WSAEventSelect(...) zurecht gemacht hab. Nun wird der Accept Event auch gebracht und mein Programm reagiert richtig, der Client Socket is auch ok (nicht INVALID). Nun bin ich sicher, dass Daten kommen müssten. aber recv(...) bringt -1 zurück. Da stimmt was nicht.
Ich habe mit WSAGetLastError(); die 10035 erhalten:Ein nicht blockierender Socketvorgang konnte nicht sofort ausgeführt werden.
Supi, das hilft mir auch nicht weiter. Ich hoffe Ihr könnt sagen, was da passiert, das eigentlich merkwürdige ist, setze ich einen Breakpoint vor die Stelle funktioniert es wunderbar. Ich poste den Code mal dazu, vielleicht kann man dann was erkennen:
... // Socket initialisieren addr.sin_family = AF_INET; ini.read_ini("options.ini","port1",wert); // eigene Funktion für Port aus INI addr.sin_port = htons (atoi(wert)); addr.sin_addr.s_addr = htonl (INADDR_ANY); server = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); if (server == INVALID_SOCKET) { AfxMessageBox("Es konnte kein Server Socket erstellt werden!"); return 1; } // Socket binden if (bind(server, (LPSOCKADDR)&addr, sizeof(addr)) == SOCKET_ERROR) { AfxMessageBox("Der Socket konnte nicht an den Port gebunden werden!"); return 1; } //den Socket auf dem Port "lauschen" lassen listen(server, SOMAXCONN); //Events erstellen und binden KillEvent = CreateEvent(0,FALSE,FALSE,NULL); SocketEvent = CreateEvent(0,FALSE,FALSE,NULL); error = WSAEventSelect(server,SocketEvent,FD_ACCEPT); error = WSAGetLastError(); //Eventarray für "WaitForMutipleObjects()" hArray[0] = SocketEvent; hArray[1] = KillEvent; while(activ) { y = recv(client,temp,512,0); if(y == -1) { error = WSAGetLastError(); //hier steigt er aus und die Gegenstelle schließt danach weil Socket wech closesocket(client); ResetEvent(SocketEvent); break; } temp[y] = 0; empfang = empfang + temp; if(empfang.Find(9,0) == -1) continue; else sprintf(buffer,"%s",empfang); switch(buffer[0]) { ... } ... }
Schonmal vielen Dank für Eure Mühen, das Zeug zu lesen.
Viele Grüße,
Ranger
-
WSAEventSelect setzt den Socket in den Non-Blocking Mode. Ein WSAEWOULDBLOCK (10035) ist somit völlig normal.
-
Danke!
Diese Information hilft mir weiter, nun muss ich nur noch herausfnden, wie ich den Socket wieder in Blocking Mode bekomme. Da schau ich mal in der MSDN. Das muss ich wohl in der Hilfe überlesen haben, dass er dn Status umsetzt.
Nochmals vielen Dank,
Ranger
-
Hallo,
ich verstehe dabei eines nicht, der server wird auf non Blocking gestellt, aber der Fehler tritt am Client Socket auf, gilt das Gleiche dann auch für den?
Müsste ich dort eigentlich nicht einfach wieder eine solche WaitforSingleObjekt() Abarbeitung einbauen, die dann auf ein FD_READ Event wartet (den müsste ich natürlich vorher noch erstellen und verknüpfen)?
Wäre das die Lösung oder ist das blockieren des Sockets die einzige Chance?
Viele Grüße,
Ranger
-
Du verwendet keine MFC. In der MFC gibt es z.B. CAsyncSocket.
Möchtest Du nach WINAPI?
-
Hallo Unix-Tom,
wenn es so ist, kannst Du mich gern dahin verschieben. Ich arbeite meist unter MFC und verwende dann API Funktionen auch dort. Solange es funktioniert mache ich mir da keinen Kopf, leider muss ich sagen.
Danke für den Hinweis.
Ranger
-
Die nötige Funktion heisst ioctlsocket:
u_long param = 0; // 0 für blocking, != 0 für non-blocking int rc = ioctlsocket(my_socket_handle, FIONBIO, ¶m); assert(rc == 0);
-
Hallo!,
Also ich hab es so versucht und habe den Fehler bekommen, der da in der Hilfe beschrieben steht, wenn ich es so anwende:
/////////////////////////////////////////////
The WSAAsyncSelect and WSAEventSelect functions automatically set a socket to nonblocking mode. If WSAAsyncSelect or WSAEventSelect has been issued on a socket, then any attempt to use ioctlsocket to set the socket back to blocking mode will fail with WSAEINVAL. To set the socket back to blocking mode, an application must first disable WSAAsyncSelect by calling WSAAsyncSelect with the lEvent parameter equal to zero, or disable WSAEventSelect by calling WSAEventSelect with the lNetworkEvents parameter equal to zero.
/////////////////////////////////////////////Nun hab ich das gelesen uns dachte mir da kann was nicht stimmen. Im Quelltext is ja ersichtlich, dass ich den Client nach dem Accept erhalte und die Blockierung auf diesen anwende. Ich frage mich, warum der Client Socket ebenfalls nonblocking ist. Hier steht, dass WSAEventSelect den Socket auf nonblocking stellt, aber doch den Server Socket oder verstehe ich da was falsch? Da stimmt doch was nicht?
Verstehe ich da was komplett falsch, ich hab langsam den Eindruck.
Viele Grüße,
Ranger
-
Nochmal ich!
Inzwischen habe ich eine Variante, bei der ich dachte sie müsste funktionieren. Aber das Problem ist, ich muss vor das recv() eine Sleep(1000) - wobei die Sekunde nur zufällig gewählt ist - setzen, damit das funktioniert und das ist nicht die feine englische.
Ich stelle nochmal den Code rein, den ich jetzt habe:// Socket initialisieren addr.sin_family = AF_INET; if(disp_nr == 1) { ini.read_ini("options.ini","port1",wert); addr.sin_port = htons (atoi(wert)); } if(disp_nr == 2) { ini.read_ini("options.ini","port2",wert); addr.sin_port = htons (atoi(wert)); } addr.sin_addr.s_addr = htonl (INADDR_ANY); // einen Socket erstellen für die jeweilige Aufgabe server = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); if (server == INVALID_SOCKET) { AfxMessageBox("Es konnte kein Server Socket erstellt werden!"); owner->ThreadStartet = false; return 1; } // Socket binden if (bind(server, (LPSOCKADDR)&addr, sizeof(addr)) == SOCKET_ERROR) { AfxMessageBox("Der Socket konnte nicht an den Port gebunden werden!"); owner->ThreadStartet = false; return 1; } //den Socket auf dem Port "lauschen lassen" listen(server, SOMAXCONN); //Events erstellen und binden KillEvent = CreateEvent(0,FALSE,FALSE,NULL); ClientEvent = CreateEvent(0,FALSE,FALSE,NULL); SocketEvent = CreateEvent(0,FALSE,FALSE,NULL); error = WSAEventSelect(server,SocketEvent,FD_ACCEPT); error = WSAGetLastError(); //Eventarray für "WaitForMutipleObjects()" hArray[0] = SocketEvent; hArray[1] = KillEvent; while(activ) { if(!activ) break; erg = WaitForMultipleObjects(2,hArray,FALSE,50); if(erg == WAIT_TIMEOUT) continue; //Timeout ohne Event if(erg == WAIT_OBJECT_0) //Event für Accept ist passiert { strcpy(buffer,""); empfang = ""; //Ethernet Event accept client = accept(server, (struct sockaddr*)&from,&fromlen); if(client == INVALID_SOCKET) { error = WSAGetLastError(); continue; } error = WSAEventSelect(client,ClientEvent,FD_READ); error = WSAGetLastError(); hArray_2[0] = ClientEvent; hArray_2[1] = KillEvent; erg = WaitForMultipleObjects(2,hArray_2,FALSE,50); if(erg == WAIT_TIMEOUT) continue; //Timeout ohne Event if(erg == (WAIT_OBJECT_0 + 1)) //Kill Event ausgelöst, Thread geht zuende { activ = false; continue; } if(erg == WAIT_FAILED) //Fehler beim Prüfen auf Events { err = GetLastError(); help.Format("Systemfehler: %i",err); AfxMessageBox(help); continue; } // eigentliche Abarbeitung starten if(erg == WAIT_OBJECT_0) { Sleep(1000); // das ist der unschöne Befehl an der Sache while(activ) { y = recv(client,temp,512,0); if(y == -1) { error = WSAGetLastError(); closesocket(client); ResetEvent(SocketEvent); AfxMessageBox("Nich gut"); break; } // ab hier liest er dann korrekt, aber nur, wenn ich die Sleep Sekunde einbaue
Das Problem ist, das zweite WaitForMultipleObjects() liefert mir zurück, dass etwas gelesen werden kann, wenn ich aber das recv() ausführe bekomme ich -1 mit der 10035 raus.
Ich war der Meinung, dass die WaitForMultipleObjects() Funktion solange wartet, bis wirklich etwas zu lesen da ist, beim Accept funktioniert das doch auch.Kann mir jemand helfen und mir zeigen, was da falsch läuft?
Vielen Dank,
Ranger