[wxWidgets] Problem mit Sockets. Anwendung blockiert.



  • phlox81 schrieb:

    Und Client und Server laufen im selben Program?
    Also ideal ist das natürlich nicht, wenn auf jeden Container jeweils der Client und Serverpart zugreifen muss.
    Überdenke hier mal dein Design.

    Ja, Client und Server laufen im selben Programm. Das muss auch so bleiben.

    Natürlich ist es nicht so ideal, dass beide auf den std::vector zugreifen, aber ich wüsste auch keine Möglichkeit das zu verhindern. Vielleicht sollte ich mal versuchen die Zugriffe darauf mit Events zu realisieren. Allerdings möchte ich nicht soooo viel Code schreiben nur um ein Event zu erstellen. Gibt es keine Möglichkeit das kürzer zu fassen? Danke.


  • Mod

    Hm, vector ist nicht so ideal dafür.
    Wenn es so ist, das an einem ende geschrieben wird, also neue verbindungen rein kommen, und am anderen Ende gelesen/gelöscht von der Sessionverwaltung,
    dann würde ich es mal mit einer std::list versuchen, da sind die Elemente unabhängiger vom Container.



  • Ich habe jetzt das Programm nochmal ganz genau unter die Lupe genommen.
    Es scheint mir, dass sich die Events des Servers und des Clients überschneiden. Und zwar versucht der Server etwas zu lesen, aber sein Buffer ist leer und der Client hat eben auch ein Event "abgefeuert" und versucht nun auch zu lesen. Tja, insgesamt scheint das dann in einem rekusiven Aufruf von wxYield zu Enden.
    Hab schon im Internet gesucht und es scheint kein Einzelfall zu sein.

    Wenn ich als Flag wxSOCKET_NOWAIT festlege, dann scheint das Problem nicht mehr aufzutreten, aber ich habe ein neues Problem: Die Daten werden wohl nicht mehr vollständig eingelesen. Was sollte ich also nun tun?

    Ich versuche während ich auf eure Antworten warte mal mein Glück mit WaitForRead und Konsorten. Allerdings vermute ich, dass ich dann das gleiche Problem bekommen werde.



  • Ich denke, ich muss mich damit abfinden, dass ich mit dem aktuellen Ansatz nicht weiter kommen werde. Ich kann das Problem leider nicht beheben, aber vermutlich umgehen, wenn ich auf asynchrone Sockets umsteige. Allerdings habe ich bisher nur mit synchronen Sockets gearbeitet und habe daher ein paar Fragen.

    Wenn ich mit einem asychronen Socket etwas sende, dann kann ich mich nicht darauf verlassen, dass auch tatsächlich alles gesendet wurde, oder?
    Wie soll ich damit umgehen? Ich müsste den nicht gesendeten Teil des Buffers ja irgendwo zwischenspeichern, damit ich ihn später senden kann?
    Und es wird ja dann wxSOCKET_OUTPUT ausgelöst, wenn ich wieder schreiben kann?

    Beim Lesen kann ich wohl auf keinen Fall davon ausgehen, dass ich alle Daten "in einem Rutsch" bekomme. Dabei habe ich noch zusätzlich das Problem, dass mein Protokoll aus 3 Teilen besteht: <Session-Key: 6 Byte><Datenlänge: 6 Byte><Daten: Anz. der Byte steht in der Datenlänge>

    Die ersten beide Teile haben fest definierte Größen.

    Ich müsste wohl eine Art State Machine nutzen? Vielleicht sowas:

    STATE_SESSION_KEY
    STATE_DATA_LEN
    STATE_DATA
    STATE_FINISHED
    

    Und wenn STATE_FINISHED erreicht wurde, dann können die Daten behandelt werden. Ist das der richtige Ansatz oder ist das total falsch?

    Freue mich schon auf eure Antworten 🙂

    Viele Grüße
    Jacob


  • Mod

    Also bei asio wird auch asynchron natürlich alles gesendet. Es ist lediglich so, das das ein anderer Thread/prozess macht, und es asynchron abläuft.
    Somit ist dein Programm nicht blockiert.

    Ich denke du bräuchtest einfach nur einen Thread fürs senden, und einen Mutex für die Liste der Daten.
    Evtl. kopierst du die einfach auch, wenn x neue verbindungen da sind, und verschickst dann die Kopie.



  • phlox81 schrieb:

    Also bei asio wird auch asynchron natürlich alles gesendet. Es ist lediglich so, das das ein anderer Thread/prozess macht, und es asynchron abläuft.
    Somit ist dein Programm nicht blockiert.

    Ich denke du bräuchtest einfach nur einen Thread fürs senden, und einen Mutex für die Liste der Daten.
    Evtl. kopierst du die einfach auch, wenn x neue verbindungen da sind, und verschickst dann die Kopie.

    Eigentlich würde ich gerne bei wxSocket bleiben und es damit lösen. Ich habe mal versucht eine kleine Beispielanwendung zu programmieren.
    Allerdings sind mir dabei ein paar - für mich - merkwürdige Dinge passiert. Die entsprechenden Stellen im Quellcode sind mit einem "FIXME" gekennzeichnet. Würde mich über ein paar Erklärungen freuen. Vielleicht habe ich ja einiges sogar zu umständlich gelöst.

    http://www.file-upload.net/download-1473634/Minimum.zip.html

    Danke 👍


  • Mod

    Ich hab leider keine Zeit mir das genauer anzuschauen, evtl. postest du mal die betreffenden Bereiche im Board.

    Wie gesagt, kann es sein, das schon eine std::list dir weiterhilft, wenn du sicher gehst, das die Clients nur lesen wenn mehr als ein element vorhanden ist.
    Ansonsten müsstest du dir da einen Mutex drum bauen, oder den Container entsprechend kopieren.



  • Zum Beispiel stürzt folgendes ab:

    void Server::OnServerEvent(wxSocketEvent& ev)
    {
    	switch (ev.GetSocketEvent())
    	{
    		case wxSOCKET_CONNECTION:
    			for (int i = 0; i < C_CONNECTIONS; ++i)
    			{
    				if (clients[i]->IsDisconnected())
    				{
    					if (server->AcceptWith(*clients[i], false))
    					{
    						clients[i]->SetFlags(wxSOCKET_NOWAIT);
    
    						clients[i]->SetEventHandler(*this, SERVER_CLIENTS_ID);
    						clients[i]->SetNotify(wxSOCKET_LOST_FLAG | wxSOCKET_CONNECTION_FLAG | wxSOCKET_INPUT_FLAG);
    						clients[i]->Notify(true);
    
    						// FIXME: 
    						// Was passiert für den Fall, 
    						// dass AcceptWith false zurückgibt?
    						// Kriege ich dann bei Verbindungsaufbau noch ein Event?
    
    						// FIXME:
    						// Aus Spaß sende ich dem Client jetzt mal 10 Nachrichten.
    						// => Verursacht bereits den ersten Crash. Warum?
    
    						// Mit nur 1 Nachricht(SEND_COUNT = 1) klappt es.
    
    						#if 1
    
    							const int SEND_COUNT = 10;
    
    							wxChar buf[C_BUF_SIZE];
    
    							wxSnprintf(buf, C_BUF_SIZE, wxT("Ein blöder Test."));
    
    							for (int i = 0; i < SEND_COUNT; ++i)
    							{
    								// FIXME: Wie garantiere ich, dass alles gesendet wird?
    								clients[i]->Write(buf, wxStrlen(buf) * sizeof(wxChar));
    							}
    
    						#endif
    					}
    
    					break;
    				}
    			}
    			break;
    	}
    }
    

    Außerdem werden die empfangenen Daten leider nicht korrekt terminiert. Am Ende sind noch ein paar Quadrate.

    void Client::OnSocketEvent(wxSocketEvent& ev)
    {
    	switch (ev.GetSocketEvent())
    	{
    		case wxSOCKET_INPUT:
    			wxChar buf[C_BUF_SIZE + 1];
    
    			// FIXME: Wie garantiere ich, dass alles empfangen wird?
    			ev.GetSocket()->Read(buf, C_BUF_SIZE);
    
    			// FIXME: Terminierungszeichen wird falsch gesetzt.
    			// Wie mache ichs richtig?
    
    			buf[ev.GetSocket()->LastCount()] = '\0';
    
    			if (wxMessageBox(wxString::Format(wxT("Got: '%s'"), 
    				wxString(buf, wxConvUTF8)),
    				wxT("Input"), 
    				wxOK | wxCANCEL) == wxOK)
    			{
    
    				// Und wieder zurück...
    				ev.GetSocket()->Write(buf, ev.GetSocket()->LastCount());
    			}
    			break;
    	}
    }
    


  • Das erste Problem konnte ich lösen. Es lag an den Schleife. Ich hatte leider zwei Mal den Namen i verwendet und das hat sich schließlich überschnitten.

    Jetzt bleibt noch der Fehler mit dem Terminierungszeichen, und die Frage, wie ich garantieren kann, dass trotz wxSOCKET_NOWAIT alles gelesen + geschrieben wird.


  • Mod

    Wie kommst du darauf, das bei SOCKET_NOWAIT nicht alles geschrieben oder gelesen wird?


Anmelden zum Antworten