如何确保WSASend()将发送数据?

时间:2015-02-26 20:27:46

标签: c++ sockets iocp

WSASend()将立即返回是否发送数据。但是如何确保数据将被发送,例如我的UI中有一个按钮,按下时会发送"Hello World!"。现在我想确保当用户点击此按钮时,"Hello World!"会在某个时间点发送,WSASend()可能会返回WSAEWOULDBLOCK,表示数据不会被发送,所以应该我将WSASend()括在一个循环中,直到WSASend()返回0(成功)才退出。

注意:我正在使用IOCP。

2 个答案:

答案 0 :(得分:3)

  

我应该将WSASend()包含在一个直到没有退出的循环中   WSASend()返回0(成功)

错误..不!

让UI发出重叠的WSASend请求,包括buffer / s和OVERLAPPED / s。如果,通过一些奇迹,它确实会立即恢复成功,(而且我从未见过它),你就是好的。

如果,(当:),它返回WSA_IO_PENDING,则您无法在UI按钮处理程序中执行任何操作,因为GUI事件处理程序无法等待。图形用户界面是状态机 - 您必须退出按钮处理程序并以提示方式返回到消息输入队列。如果你愿意,你可以做一些GUI的东西。也许禁用“发送”按钮,或将一些“消息发送”文本添加到备忘录组件。这就是它 - 你必须退出。

一段时间后,成功完成通知(或失败通知)将被发布到IOCP完成队列,处理程序线程将获得它。使用PostMessage,QueueUserAPC或类似的线程间通信机制来发送'某事'(例如原始WSASend中使用的缓冲区对象),返回UI线程,以便它可以对返回的结果采取行动,例如。重新启用“发送”按钮。

是的,它可以被看作是凌乱的,但它是唯一可以做到这一点的方法。

其他方法 - 轮询循环,Application.DoEvents,计时器等都是可怕的笨蛋。

答案 1 :(得分:1)

  

重叠套接字I / O

     

如果重叠操作立即完成,则WSASend返回零值,并使用发送的字节数更新lpNumberOfBytesSent参数。如果重叠操作成功启动并稍后完成,WSASend将返回SOCKET_ERROR并指示错误代码WSA_IO_PENDING。

...

  

错误代码WSA_IO_PENDING表示已成功启动重叠操作,并且稍后将指示完成。任何其他错误代码表示重叠操作未成功启动,并且不会发生完成指示。

...

正如docs中所示,您不需要在循环中包含,只需检查SOCKET_ERROR,如果最后一个错误不等于WSA_IO_PENDING,则一切都是细:

rc = WSASend(AcceptSocket, &DataBuf, 1,
             &SendBytes, 0, &SendOverlapped, NULL);
if ((rc == SOCKET_ERROR) &&
    (WSA_IO_PENDING != (err = WSAGetLastError()))) {
    printf("WSASend failed with error: %d\n", err);
    break;
}