如何在winsock中使“发送”非阻塞

Posted

技术标签:

【中文标题】如何在winsock中使“发送”非阻塞【英文标题】:How to make 'send' non-blocking in winsock 【发布时间】:2013-06-21 03:07:35 【问题描述】:

我正在制作一个程序,它以固定的时间间隔向服务器发送 UDP 数据包,如下所示:

while (!stop) 
    Sleep(fixedInterval);

    send(sock, pkt, payloadSize, flags);
 

但是不能保证周期性,因为send 是一个阻塞调用(例如,当fixedInterval 是20ms,而对send 的调用是> 20ms 时)。你知道如何将send 变成非阻塞操作吗?

【问题讨论】:

喜欢描述here 【参考方案1】:

您需要使用非阻塞套接字。发送/接收函数与阻塞或非阻塞操作的函数相同,但您必须将套接字本身设置为非阻塞。

u_long mode = 1;  // 1 to enable non-blocking socket
ioctlsocket(sock, FIONBIO, &mode);

另外,请注意使用非阻塞套接字是完全不同的。您需要确保成功处理 WSAEWOULDBLOCK 错误! :)

因此,使用非阻塞套接字可能会有所帮助,但仍不能保证准确的周期。您最好从计时器驱动它,而不是这个简单的循环,这样调用发送的任何延迟,即使在非阻塞模式下,也不会影响时间。

【讨论】:

fcntl()O_NONBLOCK 在 Windows 上不存在。 O_NONBLOCK 的 Windows 等效项是启用 FIONBIOioctlsocket() 是的,你当然是对的。我已编辑我的答案以使用正确的 windows 功能。【参考方案2】:

API ioctlsocket 可以做到。你可以如下使用它。但是你为什么不使用winsock中的I/O模型呢?

ioctlsocket(hsock,FIOBIO,(unsigned long *)&ul);

【讨论】:

谢谢,我应该使用哪种winsock I/O模式? @ZhiWang:显然是非阻塞的。 你的意思是 FIONBIO 而不是 FIOBIO ?【参考方案3】:

我的记忆在这里很模糊,因为我使用 UDP 非阻塞可能已经有 15 年了。

但是,您应该注意一些事项。

    如果您要通过公共网络,请仅发送较小的数据包。如果没有编写客户端或服务器来处理不完整的数据包,则 PATH MTU 可能会让您出错。

    确保检查您已发送您认为必须发送的字节数。当您期望看到发送 300 个字节而接收端只收到 248 个字节时,它会变得很奇怪。客户端和服务器端都必须意识到这个问题。

    请参阅here,了解 Linux 人员的一些好建议。

    有关 UDP 的 Unix 套接字常见问题解答,请参阅 here

    This 是一个很好的通用网络编程常见问题解答和示例页面。

【讨论】:

UDP 不会发送部分数据包。 您也不会接收部分数据报,要么全部要么全部,MTU也不会成为任何合理数据包大小的问题(没有必要保持特别小)。 IPv4 和 IPv6 都支持分片,效果很好(除了一些明显的丢包)。 @EJP:很多个月前我已经看到(并且必须修复)部分 UDP 数据包的问题。问题是 PMTU 和发送的固定大小的数据包比操作系统中的缓冲区大。幻数约为 8K 字节。我不记得所说的操作系统是 Netware、WinNt 3.x 还是 OS/2,但我记得必须修复它。 @Damon:8K 是合理的数据包大小吗?在 Windows 死亡之声流行的时候,还没有这个大小。 @JimR:8kiB 相当大,可能并不理想,但肯定是允许的。在当今的互联网(支持 IPv6 的路由器)上,这将生成 7 个片段。当然,这会让你更容易丢失数据包(因为 1 个片段丢失 = 整个数据包丢失),但在大多数情况下你应该仍然很好。如果一个路由器开始掉线,它通常会掉几十个,并且由于“线路噪声”而导致的数据包丢失极为罕见。 Windows 是否曾经无法处理合法数据包是无关紧要的。你不能考虑每一个历史性的失败实现。【参考方案4】:

测量发送所用的时间,然后只是休眠丢失的时间长达 20 毫秒?

【讨论】:

如果发送时间超过睡眠时间怎么办? @EJP:那么计时将与非阻塞发送一样关闭。

以上是关于如何在winsock中使“发送”非阻塞的主要内容,如果未能解决你的问题,请参考以下文章

在winsock中,我将如何阻止接受函数从另一个线程阻塞?

Select模型

winsock 服务器同时发送和接收

阻塞与非阻塞winsock的速度/性能特征

在 MFC 中使用异步过程调用中断接受 winsock 调用

如果 winsock2 套接字是非阻塞的,与之关联的 SSL 对象是不是也会表现出非阻塞行为?