我必须为我的IT学校制作一个简单的IRC客户端/服务器程序。主题要求我们使用select(2)
进行套接字轮询,但禁止我们使用O_NONBLOCK
套接字。
- 您的服务器将接受多个同时连接 注意,禁止使用
fork
。所以你应该强制使用select
- 您的服务器不得阻止 这与非阻止套接字无关(禁止使用
fcntl(s, O_NONBLOCK)
)
我想知道是否甚至可以使用阻塞套接字设计一个非阻塞服务器(它不会分叉),即使使用select(2)
。
这是一个简单的例子:假设我们有一个简单的文本协议,每行一个命令。每个客户都有一个缓冲区。当select(2)
告诉我们客户端已为read(2)
做好准备时,我们会在客户端缓冲区中找到\n
之前阅读,因此我们会处理该命令。使用非阻塞套接字,我们将阅读EAGAIN
。
现在假设我们使用阻塞套接字,恶意客户端发送没有换行符的文本。 select(2)
告诉我们数据可用,然后我们在客户端上read(2)
。但我们永远不会读到预期的\n
。系统调用将无限期地阻塞,而不是返回EAGAIN
。这是拒绝服务攻击。
是否真的可以设计一个带阻塞套接字且select(2)
(无fork(2)
)的非阻塞服务器?
答案 0 :(得分:1)
是的,你从select
告诉你准备就绪的套接字中读了一次。如果read
包含\n
,则处理该行。否则,存储收到的所有数据,然后立即返回select
。
这当然意味着,对于每个打开的套接字,您必须保持状态信息和到目前为止读取的数据缓冲区。这允许代码独立处理每个read
,而无需在返回select
之前完成整行。
答案 1 :(得分:0)
这是不可能的。
select()
块,因此调用它的程序也是如此。 Posix在阻塞模式下为send()
定义的行为是阻塞,直到所有提供的数据都被传输到套接字发送缓冲区。除非您要深入研究低水位等等,否则无法事先知道套接字发送缓冲区是否有足够的空间让任何给定的send()
无阻塞地完成,因此任何调用send()
的程序都不能阻止。
请注意,select()
无法帮助您解决此问题。它可以告诉您什么时候有某些房间,但是当足够时就不知道。