【问题标题】:handling WSA_IO_PENDING for socket ::send处理套接字的 WSA_IO_PENDING ::send
【发布时间】:2019-01-16 16:53:56
【问题描述】:

result = ::send(s, buf, length, flag)

最终会发送多少数据?当我得到result == SOCKET_ERRORWSAGetLastError () == WSA_IO_PENDING length 字节的 buf 最终会全部发送吗?

或者我需要再次尝试重新发送相同的 buf 数据?

另一方面

WSA_IO_PENDING

重叠的操作将在稍后完成。

应用程序已启动无法立即完成的重叠操作。稍后将给出完成指示 当操作完成时......

在我看来,发送操作将在稍后完成....

更新:这里提出了进一步的问题 Unexpected WSA_IO_PENDING from blocking (overlapped I/O) Winsock2 calls

【问题讨论】:

  • 你应该使用WSAGetLastError而不是getLastError
  • 已更正。谢谢。是错字...在代码中确实是 WSAGetLastError

标签: c++ windows sockets winsock2


【解决方案1】:

从您链接的文档页面:

如果没有出错,send返回发送的总字节数,可以小于len参数中请求发送的字节数。否则,返回 SOCKET_ERROR 值

如果result == SOCKET_ERROR 则没有发送任何内容。

至于WSA_IO_PENDING,如果您使用异步io,例如WSASend,可能会发生这种情况。在这种情况下,实际发送的字节数需要稍后检索,可能使用 io 完成例程。

【讨论】:

  • 谢谢。 WSA_IO_PENDING 的文档让我有点困惑
  • @rnd_nr_gen 请注意,WSA_IO_PENDING 甚至没有列在此函数的可能错误代码中。如果您使用异步 io 而不是阻止 send 调用,则可能会发生这种情况。即send不执行重叠操作。
  • ::recv 也是如此。我确实从 ::recv 得到 WSA_IO_PENDING,即使错误代码也没有列出。 (赢 10)
  • @rnd_nr_gen 正如 VTT 所说,send()recv() 不执行重叠 I/O,因此他们根本不可能报告 WSA_IO_PENDING。如果将套接字设置为非阻塞模式,send()/recv() 可以报告WSAEWOULDBLOCK,否则它们会以同步模式运行。只有启用了重叠 I/O 的函数,如 WSASend/Ex()WSARecv()RIOSend/Ex() 等才能报告 WSA_IO_PENDING
  • 那么我为什么确实至少从中获得 WSA_IO_PENDING 会很有趣。 ::recv() 我用于套接字的所有内容是#include , ws2_32.lib, ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP), ::WSAIoctl(s, _WSAIOW(IOC_VENDOR, 4), &heartbeat , sizeof(heartbeat), 0, 0, &no, 0, 0) 用于保持活动。和 MSVS2015/Win10 上的 ::send(), ::recv()
【解决方案2】:

经过一些研究和实验.. 以下是一些事实。

::socket 将启用隐式重叠属性。

可以通过::WSASocketsetsocketopt / SO_OPENTYPE 创建没有重叠属性WSA_FLAG_OVERLAPPED 的套接字,但是超时功能(例如SO_RCVTIMEO)需要重叠属性。

当使用 ::send ::recv 时,可能会出现 WSA_IO_PENDING 错误,应使用 WSAGetOverlappedResult 处理(我从 Windows 10 开始观察到这种行为)

或者,改用 ::WSARecv 或 ::WSASend。

还有未解决的问题:

更新:这里提出了进一步的问题 Unexpected WSA_IO_PENDING from blocking (overlapped I/O) Winsock2 calls

【讨论】:

  • 您不能在sendrecv 之后使用WSAGetOverlappedResult,原因很简单——这个api 没有指向WSAOVERLAPPED。那么您将在通话WSAGetOverlappedResult 中使用哪个WSAOVERLAPPED
  • 这是我最初的问题和猜测的假设。默认情况下,“发送”和“接收”阻塞调用可以有重叠的 I/O。就像您使用 MSDN 中所述的 NULL lpOverlapped 和 NULL lpCompletionRoutine 调用“WSASend”和“WSARecv”一样。在这些调用之后,您可能会收到带有 WSA_IO_PENDING 的 SOCKET_ERROR。阻塞调用有这样的错误对我来说很奇怪。我应该忽略“错误”,还是通过关闭套接字来处理它?可以使用具有 NULL 事件句柄的 WSAOVERLAPPED 调用“WSAGetOverlappedResult”。我可以用它来投票结果吗?
  • 我的意思是 'WSAGetOverlappedResult' 带有一个空的 WSAOVERLAPPED 对象。我希望 Win API 能够在这种情况下正确处理它,但是我没有找到任何可靠的参考...有什么意见吗?
  • 我的意思是 WSAGetOverlappedResult 带有一个空的 WSAOVERLAPPED 对象 - 不。这总是错误和毫无意义的。在´WSAGetOverlappedResult 中需要准确地使用指向 io 请求中使用的重叠的指针
  • 我希望 Win API 能在这种情况下正确处理它 - 不可能。指向重叠的指针是[WSA]GetOverlappedResult 的主要参数 - 没有它不可能确定 - io 是否完成,如果完成 - 带有哪个错误代码,如果没有错误 - 传输了多少字节。所有这些信息都存储在WSAOVERLAPPED 对象中。没有有效的对象 - 什么都不会
猜你喜欢
  • 2014-09-10
  • 2017-09-02
  • 2016-02-24
  • 2015-04-24
  • 2018-11-20
  • 1970-01-01
  • 2011-03-15
  • 1970-01-01
  • 2021-03-20
相关资源
最近更新 更多