一个套接字只对 recv() 函数进行非阻塞设置可行吗?

11

我希望能够调用recv()而不必阻塞,因此我想要将其设置为非阻塞模式,但我不希望在发送数据时也变为非阻塞模式。所以,是否可以仅使recv()函数的套接字变为非阻塞模式,或者阻塞/非阻塞模式会影响所有套接字函数?


1
你可以使用 MSG_PEEK 标志来查看是否有任何内容可接收。或者使用例如零超时的 select。然而,对于 TCP 套接字,这些方法仅适用于告诉您至少有 一个 字节可供接收,您不知道实际可用量。 - Some programmer dude
2
是的,但据我所知,如果有1个字节的数据,recv()函数就不会阻塞。 - Joshua
2
@Joachim Pileborg 即使我使用了 MSG_PEEKrecv() 仍然会阻塞。 - user4182981
2个回答

5
对于Windows,您可以使用ioctlsocket()将套接字设置为非阻塞模式。不幸的是,这些设置适用于套接字上的所有操作。因此,在您的情况下,您必须在接收和发送之间切换它。 记录一下: 对于Linux,您可以在recv()调用参数中使用MSG_DONTWAIT标志。单个调用将成为非阻塞。

2
这个标志不是标准的,因此它不具备可移植性。例如,在Windows winsock库中就无法使用它。 - Some programmer dude
我能不能只用这个代码:unsigned long l; ioctlsocket(s, FIONREAD, &l); 来检查是否有数据可读? - user4182981
你可以这样做来查看数据是否存在并切换回来(注意:请阅读MSDN链接上关于切换回阻塞的备注)。但是,也许你可以保持非阻塞模式,只有在send()返回错误WSAEWOULDBLOCK时才切换回来? - Christophe
所以 ioctlsocket(s, FIONREAD, &l); 也将套接字设置为非阻塞模式!看,我想要的不是看有多少数据可用,而是只想知道是否有数据可供读取。这难道不应该让我看到:recv(s, buffer, 1024, MSG_PEEK) 吗?但对我来说它不起作用,recv() 仍然被阻塞了。 - user4182981
@mahmoud_t1,我看到你刚才写的是FIONREAD,我已经注意到了。不好意思,应该是FIONBIO!你读过这个教程链接吗?这篇文章中的前两行代码。 - Christophe
显示剩余2条评论

2

无法使套接字仅对 recv() 函数非阻塞。

然而,有一种类似但有缺陷的方法,可以使用带有 FIONREAD 标志的 ioctlsocket()。例如:

unsigned long l;
ioctlsocket(s, FIONREAD, &l);

这个函数将立即返回可读取的字节数(不会阻塞),虽然不是很准确(但我们不关心这一点,因为我们使用它来知道是否有数据可读,而不是精确地知道有多少字节)。
正如我之前提到的,这种方法存在缺陷,因为它无法告诉您另一端何时断开连接,因为 recv() 在断开连接时返回 0,而此函数将在没有可用数据时返回 0!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接