0

I'm using a MFC CAsyncSocket to do some network communication in a multi-threaded environment. After several hours of trying to get the accepted sockets to accept incoming data I came across a page that states that for a CAsyncSocket's OnReceive function to be called the socket has to be in the context of the main GUI thread. Moving it to the main GUI thread has allowed the socket to start receiving data.

My question is this: does anyone know of a workaround for this? The socket was on a GUI thread before and the OnAccept was being called fine. The accepted socket could be used to send data no problem, just couldn't receive anything. I'd rather not have to re-architect this part of the software if I can avoid it.

4

1 回答 1

3

简单地为您的套接字创建一个具有自己的消息队列的单独线程会更简单吗?我认为不需要在主消息队列上创建 CAsyncSocket,只需在一些消息队列上创建即可。请参阅 CWinThread 的文档以了解如何使用自己的 MFC 兼容消息队列创建单独的线程。

不幸的是,从新线程的上下文中调用所有套接字操作至关重要。MFC 在隐藏类中使用全局状态,这些隐藏类使用线程本地存储来保存每个线程的信息,并且该信息用于 CAsynchSocket 的许多方法中。这意味着 CAsynchSocket 具有线程亲和性,您必须始终在任何线程中使用和创建它作为它的消息泵。

一种方法是创建一个 CWinThread,在该线程上创建您自己的自定义 MFC 隐藏窗口(通过在该线程的上下文中创建窗口),并在该窗口上为所有套接字操作创建消息和消息处理程序(创建、连接等)你做的。确保线程正在发送消息(“Run()”方法执行此操作),然后将消息发布/发送到您的窗口以控制您的套接字。

另外,请记住,来自套接字的回调将在与 UI 或工作线程不同的线程中进入。如果您正在更新 GUI 对象,您将需要担心竞争条件和可能的 GUI 线程关联问题。

如果您担心设计影响,只需创建自己的 CThreadSafeAsynchSocket 代理对象并通过消息传递到隐藏窗口委托给实际实现。您可以使用 SendMessage 进行阻塞操作,使用 PostMessage 进行异步操作。如果将构造函数包装在工厂对象中,则可以延迟创建套接字线程,直到需要它为止。

我能想到的最后一个问题是,您需要检测所有代理何时消失并关闭线程。您可以使用由 CThreadSafeAsynchSocket 的构造函数/析构函数管理的全局引用计数来检测何时关闭线程。即使在您关闭主应用程序窗口后,未能关闭线程也会让您的应用程序在隐藏窗口中徘徊。

于 2009-04-06T16:58:22.023 回答