www.mikrocontroller.net

Forum: PC-Programmierung CAsyncSocket-Assertion


Autor: Ampfing (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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
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
CAsyncSocket* PASCAL CAsyncSocket::LookupHandle(SOCKET hSocket, BOOL bDead)
Hier wird in der Zeile
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

Autor: Christoph Pelich (cpehonk)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Ampfing (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Christoph Pelich (cpehonk)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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

Autor: Ampfing (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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-... gepostet, 
vielleicht hat dort jemand eine Idee - wenn nicht werde ich es ohne 
CAsyncSocket versuchen...

Viele Grüße

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.