CAsyncSocket: Als Client verbinden sobald der Host vorhanden ist.
-
Moin.
Meine WinCE Anwendung soll zu einer Hostanwendung eine Socket Verbindung aufbauen. Meine Anwendung soll als Client fungieren. Dies habe ich folgendermaßen gemacht:
m_sConnectSocket.SetParent(this); m_sListenSocket.SetParent(this); //--- Versuchen als Client Verbindung //--- zu einem Server zu bekommen if(!m_sListenSocket.Create()) RETAILMSG(1,(_T("m_sListenSocket.Create: %d\n\r"), GetLastError())); if(!m_sListenSocket.Connect(_T("172.31.255.1"), 6000)) { RETAILMSG(1,(_T("m_sListenSocket.Connect: %d\n\r"), GetLastError())); }
Das funktioniert soweit auch schon gut. Nun kann es aber sein, dass die Hostanwendung später gestartet wird als meine Clientanwendung.
Wenn die Hostanwendung nicht läuft, liefert Connect WSAEWOULDBLOCK, was mir auch einleuchtet.
Wie kann ich erreichen, dass sich meine Clientanwendung mit der Hostanwedung verbindet, sobald diese gestartet wurde?
-
*push*
-
in dem du immer wieder ein Verbindungsversuch machst solang der Connect schief geht, also als Beispiel dein Connect() in einem Thread auslagerst und dort den Verbindungsversuch machst bis die Vebindung zustande gekommen ist.
-
Hallo CTecS.
Vielen Dank für Deine Antwort. Habe es mal so versucht. Ist das so richtig?
CMySocket CSocket02Dlg::m_sListenSocket; CMySocket CSocket02Dlg::m_sConnectSocket; unsigned int CSocket02Dlg::TrySocketConnect(LPVOID pParam) { m_sConnectSocket.SetParent((CDialog *)pParam); m_sListenSocket.SetParent((CDialog *)pParam); //--- Versuchen als Client Verbindung //--- zu einem Server zu bekommen if(!m_sListenSocket.Create()) RETAILMSG(1,(_T("m_sListenSocket.Create: %d\n\r"), GetLastError())); while(!m_sListenSocket.Connect(_T("172.31.255.1"), 6000)) { RETAILMSG(1,(_T("Try to Connect\n\r"))); Sleep(1000); } RETAILMSG(1,(_T("Connected now!\n\r"))); return 0; } BOOL CSocket02Dlg::OnInitDialog() { CDialog::OnInitDialog(); AfxBeginThread(TrySocketConnect, (LPVOID)this); ... ... }
Ich bekomme leider bei der Zeile if(!m_sListenSocket.Create()) die Meldung 'ASSERT_VALID fails with NULL pointer.'
Das verstehe ich nicht ganz. Führe ich den selben Code im MainThread (in OnInitDialog) aus, kommt diese Meldung nicht
Wo ist das Problem?
-
*push*
-
Viele MFC Objekte sind threadafin. D.h. Du kannst Sie nur in dem Thread benutzen, der sie erzeugt.
Du erzeugst global (im ertsen Thread) CMySocket Objekte. Diese gehören also diesem "Main-Thread". Dann bentzt Du diese aber in einem anderen Thread.
Das muss knallen.
Erzeuge Deine CMySocket Objekte in dem Workerthread!
-
Ich habe es so mal versucht, bekomme aber noch die selbe Meldung:
CMySocket *CSocket02Dlg::m_psListenSocket; CMySocket *CSocket02Dlg::m_psConnectSocket; unsigned int CSocket02Dlg::TrySocketConnect(LPVOID pParam) { m_psConnectSocket = new CMySocket; m_psListenSocket = new CMySocket; m_psConnectSocket->SetParent((CDialog *)pParam); m_psListenSocket->SetParent((CDialog *)pParam); //--- Versuchen als Client Verbindung //--- zu einem Server zu bekommen if(!m_psListenSocket->Create()) RETAILMSG(1,(_T("m_psListenSocket->Create: %d\n\r"), GetLastError())); while(!m_psListenSocket->Connect(_T("172.31.255.1"), 6000)) { RETAILMSG(1,(_T("Try to Connect\n\r"))); Sleep(1000); } RETAILMSG(1,(_T("Connected now!\n\r"))); return 0; } BOOL CSocket02Dlg::OnInitDialog() { CDialog::OnInitDialog(); AfxBeginThread(TrySocketConnect, (LPVOID)this); ... ...
private: static unsigned int TrySocketConnect(LPVOID pParam); static CMySocket *m_psListenSocket; static CMySocket *m_psConnectSocket;
Ich habe es auch mal mit lokalen Objekten im Thread probiert, aber auch die selbe Meldung:
unsigned int CSocket02Dlg::TrySocketConnect(LPVOID pParam) { CMySocket *lsListenSocket; CMySocket *lsConnectSocket; lsConnectSocket = new CMySocket; lsListenSocket = new CMySocket; lsConnectSocket->SetParent((CDialog *)pParam); lsListenSocket->SetParent((CDialog *)pParam); //--- Versuchen als Client Verbindung //--- zu einem Server zu bekommen if(!lsListenSocket->Create()) RETAILMSG(1,(_T("m_psListenSocket->Create: %d\n\r"), GetLastError())); while(!lsListenSocket->Connect(_T("172.31.255.1"), 6000)) { RETAILMSG(1,(_T("Try to Connect\n\r"))); Sleep(1000); } RETAILMSG(1,(_T("Connected now!\n\r"))); return 0; }
Was habe ich falsch gemacht?
-
*push*
-
Was macht SetParent? Warum bekommen die Socket Objekte einen Zeiger auf einen CDialog?
Sieht so aus, als würden die Socket Klassen irgendetwas mit dem Dialog machen. Das geht wohl schief.
-
Das war in einem Tutorial so beschrieben. In den Ereignishandlern der Socketklasse wird einfach nur eine Methode der Dialogfunktion aufgerufen...
Wie dem auch sei, ich habe das geändert. Sprich, die SetParent Methode wird im Thread nicht mehr aufgerufen, aber der Fehler bleibt.
Um den Fehler nochmal genauer zu beschreiben: Der Fehler tritt bei dem Aufruf von lsListenSocket.Create() auf. In dem Ausgabefenster von VS steht dann die Zeile 'ASSERT_VALID fails with NULL pointer.'
Auf dem WinCE Desktop erscheint die Fenster mit folgendem Inhalt:
Debug Assertion Failed!
Program: \Program
Files\....Socket02.exeFile:
f:\dd\vctools\vc7libsce\ship\atl
mfc\include\afxtempl.h
Line: 1707(Press Retry to debug the
application)Abort Retry Ignore
Wenn ich Retry drücke wird die Datei objcore.cpp geöffnet und es wird an folgender Stelle angehalten:
///////////////////////////////////////////////////////////////////////////// // Diagnostic Support #ifdef _DEBUG void AFXAPI AfxAssertValidObject(const CObject* pOb, LPCSTR lpszFileName, int nLine) { if (pOb == NULL) { TRACE(traceAppMsg, 0, _T("ASSERT_VALID fails with NULL pointer.\n")); if (AfxAssertFailedLine(lpszFileName, nLine)) AfxDebugBreak(); //<--- hier wird abgehalten return; // quick escape }
Wenn ich dann weiterlaufen lasse kommt:
Unhandled exception at 0x0001ca34 in Socket02.exe: 0xC0000005: Access violation.
Kann da jemand was mit anfangen?
-
*push*
-
Hat keiner eine Idee?
-
Dein CObject-Zeiger is an der Stelle NULL, also das existiert noch nicht oder nicht mehr oder wie auch immer.
-
Aber unmittelbar davor erstelle ich das Objekt doch....
Und der selbe Code funktioniert ja auch wenn ich ihn im Main Thread ausführe. Das Problem tritt nur auf wenn ich dies in einem weiterm Thread mache
-
So wie Martin Richter schon geschrieben hat, ich zitiere:
Viele MFC Objekte sind threadafin. D.h. Du kannst Sie nur in dem Thread benutzen, der sie erzeugt.
Du erzeugst global (im ertsen Thread) CMySocket Objekte. Diese gehören also diesem "Main-Thread". Dann bentzt Du diese aber in einem anderen Thread.
Das muss knallen.
Erzeuge Deine CMySocket Objekte in dem Workerthread!
Versuch mal deine CMySocket Objete nicht im Thread anzulegen, sondern beispielsweise in OnInitDialog, bevor du den Thread startest.
-
Source2702 schrieb:
Versuch mal deine CMySocket Objete nicht im Thread anzulegen, sondern beispielsweise in OnInitDialog, bevor du den Thread startest.
Die Objekte existieren doch schon, da sie Membervariablen des Dialogs sind, wenn ich das richtig verstanden hab. Du meinst sicher das das Create außerhalb des Threads passieren sollte... Das würde ich auch als nächstes testen. Damit läuft nur noch das while() im Thread.
-
Du erzeugst sie mit new im Thread, wie ich gesehen habe.
Erzeuge sie (mit oder ohne new) im Hauptthread. Sollte das Problem lösen.
-
Source2702 schrieb:
Du erzeugst sie mit new im Thread, wie ich gesehen habe.
Erzeuge sie (mit oder ohne new) im Hauptthread. Sollte das Problem lösen.Nö, denke ich nicht, wenn ich folgenden Code sehe:
CMySocket CSocket02Dlg::m_sListenSocket; CMySocket CSocket02Dlg::m_sConnectSocket; unsigned int CSocket02Dlg::TrySocketConnect(LPVOID pParam) { m_sConnectSocket.SetParent((CDialog *)pParam); m_sListenSocket.SetParent((CDialog *)pParam); //--- Versuchen als Client Verbindung //--- zu einem Server zu bekommen if(!m_sListenSocket.Create()) RETAILMSG(1,(_T("m_sListenSocket.Create: %d\n\r"), GetLastError())); while(!m_sListenSocket.Connect(_T("172.31.255.1"), 6000)) { RETAILMSG(1,(_T("Try to Connect\n\r"))); Sleep(1000); } RETAILMSG(1,(_T("Connected now!\n\r"))); return 0; } BOOL CSocket02Dlg::OnInitDialog() { CDialog::OnInitDialog(); AfxBeginThread(TrySocketConnect, (LPVOID)this); ... ... }
Die Konstruktion erfolgt eindeutig außerhalb des Threads. Aber der Ansatz, dass der Create-Aufruf außerhalb des Threads erfolgen sollte, müsste mal getestet werden.
-
Doch, doch. In seiner letzten Implementierung, die er hier gepostet hat, war es mit new drin. Auf diese hab ich mich bezogen.
Ist aber egal, es hängt höchstwahrscheinlich am Create.
-
So, ich bin wieder einen Schritt weiter. Der Tipp mit dem Create war goldrichtig. Das Create gehört in den Hauptthread, dann geht es.
Vielen Dank
Nur einen Sache funktioniert noch nicht.
Wenn die Hostanwendung nun wieder geschlossen wird, soll meine Anwendung wieder pollen und sich wieder verbinden, sobald die Hostanwendung wieder da ist.
So habe ich es versucht:
// CMySocket-Memberfunktionen void CMySocket::SetParent(CDialog * pWnd) { m_pWnd = pWnd; } void CMySocket::OnClose(int nErrorCode) { #ifdef _WIN32_WCE if (INVALID_SOCKET != m_hSocket) { RETAILMSG(1, (_T("AsyncSelect(0);\n"))); AsyncSelect(0); // switch of eventhandling } #endif RETAILMSG(1, (_T("OnClose:\n"))); CAsyncSocket::OnClose(nErrorCode); if(nErrorCode == 0) ((CSocket02Dlg*)m_pWnd)->OnClose(); }
// Socket02Dlg.cpp : Implementierungsdatei // CMySocket *CSocket02Dlg::m_psListenSocket; CMySocket *CSocket02Dlg::m_psConnectSocket; unsigned int CSocket02Dlg::TrySocketConnect(LPVOID pParam) { while(!m_psListenSocket->Connect(_T("172.31.255.1"), 6000)) { if(GetLastError() == WSAEISCONN /* (10056) Socket is already connected. */) { RETAILMSG(1,(_T("GetLastError() == WSAEISCONN -> break\n"))); break; } RETAILMSG(1,(_T("Try to Connect - Error Code: %d\n"),GetLastError())); Sleep(1000); } RETAILMSG(1,(_T("Connected now!\n"))); return 0; } BOOL CSocket02Dlg::OnInitDialog() { CDialog::OnInitDialog(); m_psConnectSocket = new CMySocket; m_psListenSocket = new CMySocket; m_psConnectSocket->SetParent(this); m_psListenSocket->SetParent(this); //--- Versuchen als Client Verbindung //--- zu einem Server zu bekommen if(!m_psListenSocket->Create()) RETAILMSG(1,(_T("m_psListenSocket->Create: %d\n\r"), GetLastError())); AfxBeginThread(TrySocketConnect, (LPVOID)this); } void CSocket02Dlg::OnClose() { RETAILMSG(1, (_T("CSocket02Dlg::OnClose: \r\n"))); m_psConnectSocket->Close(); m_psListenSocket->Close(); AfxBeginThread(TrySocketConnect, (LPVOID)this); }
Wird nun also die Verbindung Seitens der Hostanwendung geschlossen, wird das OnClose Event aufgerufen. Dort rufe ich die OnClose Funktion meiner Dialogklasse auf. In dieser starte ich wieder den 'PollThread'.
Nur wird dann keine Verbindung aufgebaut. Connect kommt immer mit dem ReturnValue WSAENOTSOCK (10038) Socket operation on non-socket. zurück.
Wo liegt hier nun wieder das Problem?