如何在 linux C 中解除对 recv() 或 recvfrm() 函数的阻塞

Posted

技术标签:

【中文标题】如何在 linux C 中解除对 recv() 或 recvfrm() 函数的阻塞【英文标题】:How to unblock recv() or recvfrm() function in linux C 【发布时间】:2012-04-25 09:06:12 【问题描述】:

当 PC 从睡眠状态恢复时,我想从 PC 向摄像头发送 UDP 数据包。由于 PC 恢复后网络接口需要一些时间(未知)才能激活,所以我不断循环发送数据包到相机。当相机接收到数据包时,它会向 PC 发送一个确认信号。 我的问题是“为了从摄像机接收 UDP 数据包(确认信号),我使用了阻止循环的 recvfrm() 函数。我如何解除阻止这个函数,以便它只有在接收到来自摄像机的确认信号时才退出循环。

【问题讨论】:

MSG_DONTWAIT 完成了这项工作,但还有另一个小问题。在网络变得活跃之前,我将数据包循环发送到相机。一旦网络恢复正常,摄像机就会接收到数据包,并将确认信号发送回 PC。问题是,在 PC 收到确认信号并退出循环之前,它仍然会向相机发送一些数据包,这些数据包在某处缓冲。下一次,相机不再等待来自 PC 的数据包,而是读取不可接受的旧数据包。我该如何避免这种情况?如何刷新/清除旧数据包? 【参考方案1】:

使用MSG_DONTWAIT 标志传递给recvfrom 函数。它启用非阻塞模式。如果操作会阻塞此调用,则返回 EAGAINEWOULDBLOCK 错误代码。

【讨论】:

【参考方案2】:

对于 maverik 的答案(否则是正确的),一个更便携的解决方案是将fcntl 套接字连接到O_NONBLOCK

MSG_DONTWAIT,虽然在 Linux 和 BSD 下可用,并且大多数 Unices 仅在 SUSv4 中标准化用于发送(为什么,我不知道......但 M. Kerrisk 这么说)。一个值得注意的不支持它的平台是 Winsock(至少在 MSDN 中没有记录)。

或者,如果您不想篡改模糊标志和fcntl,您可以select 准备就绪描述符(使用零超时,甚至使用非零超时来限制您发送的数据包——不要淹没网络堆栈可能是个好主意)。继续发送直到select 说可以读取。

【讨论】:

【参考方案3】:

最简单的方法(但不是最好的代码)是等待一段时间回复是在调用 recvfrom() 之前使用select。

【讨论】:

以上是关于如何在 linux C 中解除对 recv() 或 recvfrm() 函数的阻塞的主要内容,如果未能解决你的问题,请参考以下文章

linux c编程:信号 sigsuspend

linux解除绑定ssh源地址

如何判断对端关闭了socket

linux 下调用recv函数,死循环在recv函数里面,啥原因?

Linux Socket

Linux中如何解除最大进程数和最大文件句柄打开数限制?