不使用O_NONBLOCK时避免发送阻塞

问题描述 投票:0回答:3

我必须使用 unix 套接字(没有 O_NONBLOCK)为一个类编写一个聊天客户端-服务器,并在它们上选择异步 I/O。目前,在服务器上,我从客户端读取了1024字节,并直接处理它。

例如,在消息的情况下,我将收到格式为

MSG <msg>
的命令(代表客户端发送消息),我将遍历已连接客户端的所有套接字并在其上写入消息。

这种方法确实有效,但我最近通过阅读

send
的人发现,如果套接字缓冲区已满并且套接字上未设置 O_NONBLOCK 标志,它可能会阻塞。

我认为当客户端由于某些原因(崩溃、错误等)不读取时可能会发生此问题,这对我的服务器至关重要,因为它基本上会阻塞,直到该客户端再次读取。

所以这是我的问题:

对于潜在阻塞的套接字,如果套接字缓冲区已满,避免发送阻塞的正确方法是什么?

我目前仅使用 select 来检查套接字上是否有可读取的内容,但也许我也应该使用它来查看是否也可以在特定套接字上写入?另外,我可以知道 select 返回时可以读/写多少字节吗?例如,如果 select“告诉”我可以在这个套接字上写入,那么在这个套接字上写入实际上变成阻塞之前,我如何知道最多可以写入多少字节?

c sockets unix posix-select
3个回答
1
投票

您可以将

setsockopt()
SO_SNDTIMEO
一起使用来设置
send()
尝试完成其工作的最大时间。

详情请参阅

man setsockopt
man 7 socket


0
投票

这可能很可怕。如果您不进入 NONBLOCK 模式并调用 select(),这会在内部将进程置于睡眠状态以达到特定的超时值。这意味着 fd 将在该特定时间段内被阻止。


0
投票

这种方法确实有效,但我最近通过阅读 send 的 man 发现,如果套接字缓冲区已满并且套接字上未设置标志 O_NONBLOCK ,它可能会阻塞。

这就是您使用 select 的原因,但它仍然不可靠,如

man select
所示:

在 Linux 下,select() 可能会将套接字文件描述符报告为“已准备好读取”,但后续读取会阻塞。例如,当数据有 已到达,但经检查校验和错误并被丢弃。可能存在文件描述符被错误地报告为就绪的其他情况。因而可能 在不应阻塞的套接字上使用 O_NONBLOCK 会更安全。

© www.soinside.com 2019 - 2024. All rights reserved.