4

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

例如,在消息的情况下,我将收到一个格式为MSG <msg>(代表客户端发送消息)的命令,我将遍历已连接客户端的所有套接字并将消息写入它们。

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

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

所以这是我的问题:

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

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

谢谢。

4

3 回答 3

1

您可以使用setsockopt()withSO_SNDTIMEO来设置send()将尝试完成其工作的最大时间量。

有关详细信息,请参见man setsockoptman 7 socket

于 2013-04-25T10:34:44.860 回答
0

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

这就是您使用 select 的原因,但它仍然不可靠,如下man select所述:

在 Linux 下,select() 可能会将套接字文件描述符报告为“准备好读取”,但随后会出现读取块。例如,当数据到达但检查时校验和错误并被丢弃时,可能会发生这种情况。可能存在文件描述符被虚假报告为就绪的其他情况。因此,在不应阻塞的套接字上使用 O_NONBLOCK 可能更安全。

于 2013-08-05T10:14:52.223 回答
0

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

于 2013-04-25T10:59:33.000 回答