2009-04-06 5 views
0

Ich verwende eine MFC CAsyncSocket, um einige Netzwerkkommunikation in einer Umgebung mit mehreren Threads auszuführen. Nachdem ich mehrere Stunden lang versucht habe, die akzeptierten Sockets zur Annahme ankommender Daten zu bekommen, stieß ich auf eine Seite, die besagt, dass der Socket für eine CAsyncSocket-OnReceive-Funktion im Kontext des Haupt-GUI-Threads stehen muss. Durch Verschieben in den Haupt-GUI-Thread konnte der Socket Daten empfangen.CAsyncSocket und Threading

Meine Frage ist dies: Kennt jemand eine Abhilfe für diese? Der Socket war zuvor in einem GUI-Thread und der OnAccept wurde als gut bezeichnet. Der akzeptierte Socket könnte verwendet werden, um Daten zu senden, kein Problem, konnte einfach nichts empfangen. Ich würde diesen Teil der Software lieber nicht neu entwerfen müssen, wenn ich es vermeiden kann.

Antwort

3

Wäre es einfacher, einfach einen separaten Thread mit einer eigenen Nachrichtenwarteschlange für Ihre Sockets zu erstellen? Ich glaube nicht, dass CAsyncSocket in der Hauptnachrichtenwarteschlange erstellt werden muss, sondern nur in einer Nachrichtenwarteschlange. Weitere Informationen zum Erstellen eines separaten Threads mit einer eigenen MFC-kompatiblen Nachrichtenwarteschlange finden Sie in der Dokumentation zu CWinThread.

Leider ist es wichtig, dass Sie alle Socket-Operationen aus dem Kontext des neuen Threads aufrufen. MFC verwendet den globalen Status in versteckten Klassen, die lokalen Threadspeicher verwenden, um Informationen pro Thread aufzunehmen, und diese Informationen werden in vielen Methoden von CAsynchSocket verwendet. Das bedeutet, dass CAsynchSocket eine Thread-Affinität hat und Sie sie immer in jedem Thread verwenden und erstellen müssen, der seine Nachrichtenpumpe sein soll. Ein Ansatz besteht darin, ein CWinThread zu erstellen, ein eigenes benutzerdefiniertes MFC-Fenster in diesem Thread zu erstellen (indem das Fenster im Kontext dieses Threads erstellt wird) und in diesem Fenster Nachrichten und Nachrichtenhandler für den gesamten Socket zu erstellen Operationen (Erstellen, Verbinden, usw.) tun Sie. Stellen Sie sicher, dass der Thread Nachrichten pumpt (die "Run()" -Methode macht dies) und posten/senden Sie dann Nachrichten an Ihr Fenster, um Ihre Socket (s) zu steuern.

Denken Sie auch daran, dass Callbacks von Ihrem Socket in einem separaten Thread als Ihre UI- oder Arbeitsthreads eingehen. Bei der Aktualisierung von GUI-Objekten müssen Sie sich über Race Conditions und möglicherweise Probleme mit GUI-Thread-Affinität Gedanken machen.

Wenn Sie sich Gedanken über die Auswirkungen auf das Design machen, erstellen Sie einfach Ihr eigenes CThreadSafeAsynchSocket-Proxyobjekt und delegieren Sie an die reale Implementierung durch Nachrichtenübergabe an Ihr ausgeblendetes Fenster. Sie können SendMessage für blockierende Vorgänge und PostMessage für asynchrone Vorgänge verwenden. Wenn Sie den Konstruktor in ein Factory-Objekt einfügen, können Sie die Erstellung des Socket-Threads verzögern, bis er benötigt wird.

Die letzte Sorge, die ich denken kann, ist, dass Sie erkennen müssen, wenn alle Ihre Proxies gegangen sind und den Thread herunterfahren. Sie können eine globale Verweisanzahl verwenden, die von den Konstruktoren/Destruktoren von CThreadSafeAsynchSocket verwaltet wird, um zu erkennen, wann der Thread heruntergefahren werden muss. Wenn Sie den Thread nicht beenden, bleibt Ihre App auch dann in einem verborgenen Fenster hängen, wenn Sie das Hauptfenster der App schließen.

+0

Mein ursprünglicher Code verwendet einen Thread mit einer Nachrichtenpumpe (getestet und funktioniert mit dem Senden über den Socket), aber immer noch nicht für den OnReceive aufgerufen werden. – Noaki

+0

Probieren Sie einen vollständigen GUI-Thread mit einem ausgeblendeten Fenster aus. –