Forum: PC-Programmierung CAsyncSocket-Assertion


von Ampfing (Gast)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,

ich habe ein MFC-Projekt, in dem ich einen Socket zur 'Fernsteuerung' 
der Applikation implementieren möchte. Das Ganze ist eine 
Single-Threaded-Anwendung. Wenn also der Socket blockiert blockiert die 
komplette Anwendung (das ist gewollt so).
Aus diesem Grund hatte ich folgende Idee:
1. Der Socket wird als nicht-blockierend konfiguriert und prüft 
zyklisch, ob sich ein Client mit ihm verbinden möchte. Bei vorhandenem 
Client wird die Verbindung aufgebaut.
2. Wird ein bestimmtes 'Telegram' über den Socket empfangen (erstes Byte 
== 0), wird der Socket umkonfiguriert (blockierend) und es wird auf 
weitere Daten von außen gewartet. Solange keine Daten kommen steht auch 
die Applikation. Werden Daten von außen empfangen wird darauf reagiert 
(bei bestimmten Objekten etwas geändert,...) und auf das nächste 
Kommando gewartet
3. Wird ein anderes Telegram (erstes Byte == 1) empfangen wird der 
Socket wieder umkonfiguriert (nicht-blockierend) und es geht bei Punkt 2 
wieder von vorne los

Das funktioniert mit dem angehängten Code auch schon ganz gut.

Folgende Fragen/Probleme stellen sich allerdings:
1. Ich muss die Funktion AfxSocketInit() mehrmals aufrufen. Speziell der 
Aufruf in der zyklischen Funktion (HandleTimerEvent()) stört mich. Habe 
mir die Funktion mal angeschaut, dort werden - wenn Pointer auf NULL 
zeigen - Objekte mit new erzeugt. In diese Fälle läuft er auch jedesmal 
rein. Produziere ich dadurch irgendwo ein Speicherleck??? Wenn ich die 
Funktion dort nicht rufe geht aber der Aufruf
1
if (0 != m_ListenSocket.Accept(m_CommSocket))
 schief (Debug-Assertion)

2. Neim Beenden der Applikation bekomme ich eine Debug-Assertion in der 
Datei sockcore.cpp in der Funktion
1
CAsyncSocket* PASCAL CAsyncSocket::LookupHandle(SOCKET hSocket, BOOL bDead)
Hier wird in der Zeile
1
pSocket = (CAsyncSocket*)pState->m_pmapSocketHandle->GetValueAt((void*)hSocket);
 auf einen Pointer zugegriffen, der an dieser Stelle NULL ist.

Kann mir bitte jemand erklären, warum der Pointer NULL ist? Und ob es 
tatsächlich sinnvoll/nötig ist AfxSocketInit() so oft zu rufen.

Vielen Dank im voraus und viele Grüße

von Christoph P. (cpehonk)


Lesenswert?

Hi,

würde ich etwas anders lösen.

Der "Listen"-Socket ist NICHT der Kommunikations-Socket. In Moment des 
Akzeptierens einer Verbindung wird ein neuer Socket erstellt. Über 
diesen läuft dann der Datenaustausch ab.

Ich würde folgendes imlpementieren:

1.) Listen-Socket als SOCK_STREAM (blockierend) erstellen und an den 
entsprechenden Port binden (bind())

2.) Mittels der Funktion "select()" kann nicht blockierend geprüft 
werden, ob am Listen-Socket Daten anstehen. Ein Verbindungswunsch 
entspricht dem Übermitteln von Daten und hat zur Folge, dass das 
"select()" für den Listen-Socket (Socket-Descriptor für Lesen übergeben 
!) signalisiert, dass hier Daten anstehen.

3.) "accept()" aufrufen und mit dem zurückgelieferten Socket für die 
Kommunikation arbeiten.

Ich würde auf die Standard-Socket Funktionen zurückgreifen 
("Berkley-Sockets"). Sind in "winsock2.h" vorhanden. Der Include 
"afxsock.h" nimmt dies aber bereits ab.

Die Funktion AfxSocketInit() sollte nur EINMAL in der 
Initialisierungsroutine der Anwendung aufgerufen werden. Nicht mehrmals.
Implementiert man bei der MFC i.Allg. unter der Funktion 
"InitInstance()".

Viele Grüße
Christoph

von Ampfing (Gast)


Lesenswert?

Guten Morgen,

vielen Dank für die Antwort.
Wo liegt der Vorteil Deiner Vorgehensweise? Auch bei mir gibt es zwei 
Socket-Objekte - eines zum Hören auf den Port (m_ListenSocket), eines 
für die Kommunikation (m_CommSocket). Im Prinzip mache ich genau das, 
was Du mir vorschlägst - nur mit anderern Funktionen - oder? Zumindest 
sehe ich erstmal in der Vorgehensweise keinen nennenswerten Unterschied.

Das AfxSocketInit() nur einmal aufgerufen werden sollte hatte ich 
vermutet. Allerdings bringen mir eben verschiedene Socket-Operationen 
eine Debug-Assertion, wenn ich AfxSocketInit() nicht mehrmals aufrufe - 
eben z.B. der Aufruf von Accept() in HandleTimerEvent(). Hab den Aufruf 
von AfxSocketInit() auch in die InitInstance reingesetzt, ändert aber 
leider nichts an der Tatsache, dass das Programm die Assertion 
verursacht.

Leider ist das ganze Projekt deutlich zu groß, um es hier zu posten. 
Hast Du (oder natürlich auch gerne jemand anders) noch einen Vorschlag, 
wie ich dem Ganzen auf die Spur kommen könnte?

Viele Grüße

von Christoph P. (cpehonk)


Angehängte Dateien:

Lesenswert?

In den MFC-Klassen passiert zuviel, auf das man keinen Einfluss hat. Das 
Debuggen wird damit oft sehr schwer (wie Du gerade erlebst). Ich habe 
einmal ein Fragment Deiner Klasse auf die Art umgeschrieben, wie ich es 
machen würde.

Ich sehe in Deinem Code ein paar Probleme:

* die Sockets sind nicht Member der Klasse und damit Instanz-unabhängig
* AfxSocketInit() rufst Du ggfs. deutlich mehrmals auf (100ms Timer)
* ich sehe kein shutdown der sockets (was jedoch in der Close() Funktion 
schon implementiert sein mag)

Viele Grüße

von Ampfing (Gast)


Lesenswert?

Hi Christoph,

danke für Deine Mühen meinen Code umzuschreiben.
Mittlerweile habe ich es auch noch auf eine andere Art versucht (wieder 
mit MFC-Klassen), bin aber leider zum gleichen Ergebnis gekommen...
Habe noch unter 
http://www.c-plusplus.de/forum/viewtopic-var-t-is-248535.html gepostet, 
vielleicht hat dort jemand eine Idee - wenn nicht werde ich es ohne 
CAsyncSocket versuchen...

Viele Grüße

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.