如何防止WSASend()阻止我的UI线程?

时间:2015-02-22 19:37:58

标签: c++ windows sockets winapi network-programming

我想使用Overlapped I / O和Completion Routine来处理客户端连接。

在我的UI线程中,我想使用WSASend(),但为了让系统调用我的回调函数来通知我数据已经发送,UI线程必须处于等待状态,但这样做冻结我的UI!

我该如何解决这个问题?

1 个答案:

答案 0 :(得分:1)

我同意@DavidHeffernan - UI线程应该做UI事情。 IO线程肯定需要绑定和端口,(服务器)或对等地址和端口(客户端)。 ConnectEx或AcceptEx中的套接字肯定会更好地加载到IO线程中,但是一个带有(此时是未定义的)套接字的套接字成员肯定可以在UI线程中创建并发送到IO线程进行处理。缓冲区是否构成Socket类的一部分,或者是一个单独的Buffer类,是一个设计考虑因素。

一个实现,(我已成功使用):

设计/定义一个' Inter Thread Comms',(ITC'),消息类。这有一个'命令'枚举成员可以告诉其他线程做的事情,以及这样的消息中可能需要的任何其他有用的东西

导出一个' Socket'来自ITC的课程。它具有IP /端口的字符串成员,套接字句柄以及可能需要的任何其他内容。

导出一个'缓冲区'来自ITC的课程。这有一个' BoundSocket'会员,缓冲空间和过度使用的'结构

使用IO线程的通信相当容易。由于它必须等待一些可以改变的东西,它可以等待管理“命令”的信号量。 ConcurrentQueue。

如果UI希望指示IO线程连接到服务器,它会创建一个Socket实例(新),从UI元素加载IP和端口成员,将命令枚举设置为' Connect',将套接字推送到Commands队列并发信号通知信号(ReleaseSemaphore)。

IO线程中的可警告等待然后返回WAIT_OBJECT_0,(它需要忽略WAIT_IO_COMPLETION返回),因此知道命令已排队。它从Commands队列中弹出它并对命令枚举(可能是打开它)执行操作,以执行所需的操作。对于连接,这将涉及重叠的ConnectEx'调用排队连接请求并设置连接完成处理程序。

连接完成处理程序在被调用时会检查成功连接,如果是,可以新建一个Buffer,加载它,发出一个WSARecv,服务器发送东西并将返回的Socket对象存储在容器中。如果失败,它可以加载Socket 使用合适的错误消息并将PostMessage返回到UI线程,以通知用户失败。

请参阅 - 它并不困难,不需要10000行代码:)

我唯一不知道如何立即做的就是获得这个'这个'从完成例程中返回的OVERLAPPED结构返回套接字对象。在32位系统上,我推动了Buffer'这个'进入Buffer实例中重叠结构的hEvent字段,并将其强制转换为完成例程。 Buffer实例有一个Socket引用,因此完成了工作。在64位系统上,hEvent没有足够的空间来存储48/64位'这个'缓冲区指针和(突然),这需要一个扩展的OVERLAPPED结构:(不确定如何完成 - 也许你会发现:)

[编辑] @BenVoigt对32/64位提出建议'获取套接字上下文'这个'回到完成例程'问题 - 它比我想象的容易:): https://stackoverflow.com/a/28660537/758133