在服务器中使用 select() 处理新客户端的最佳方法是什么?
我想用 C 语言编写一个异步套接字服务器,但在此之前我正在做一些研究。查看此处显示的 select() 套接字示例: http://www.gnu.org/s/hello/manual/libc/Server-Example.html#Server-Example 我可以看到示例程序每个选择循环仅接受一个客户端(如果我'我读对了)。因此,如果有 20 个客户端并且另外两个客户端尝试连接,它是否只接受第 21 个客户端,然后处理其他 20 个客户端(最坏的情况,假设所有其他 20 个客户端都需要读取),然后接受第 22 个客户端?如果我在接受客户端后中断循环,以便它可以再次 select() 并在处理连接的客户端之前处理所有待处理的客户端,会更好吗?或者这是否违背了使用 select() 的目的?谢谢。
I want to write a asynchronous socket server in C, but before I do I'm doing some research. Looking at the select() socket example shown here: http://www.gnu.org/s/hello/manual/libc/Server-Example.html#Server-Example I can see that the example program will only accept one client per select loop (if I'm reading it right). So if there are 20 clients and two more try to connect, will it only accept the 21st client then process the other 20 (worst case, assuming all 20 others require reading) and THEN accept the 22nd? Would it be better if I break the loop after accepting a client so it can select() again and take care of all pending clients before processing connected ones? Or does that defeat the purpose of using select()? Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您可以在accept()之后在监听套接字上使用poll()来查看是否有更多客户端等待连接。
请注意,并发连接尝试的数量由listen(server_sock, backlog) 的backlog 参数处理 - 在您引用的示例中backlog 为1。
You can use poll() on the listening socket after accept() to see if there are more clients waiting to connect.
Note the the number of concurrent connect-attempts is handled by the backlog parameter to listen(server_sock, backlog) - backlog is 1 in the sample you reference.
您链接到的示例中显示的服务器模式很好;每次迭代只接受一个套接字的循环不会带来任何重大问题。
要记住的关键点是,在设计良好的 select() 循环中,进程唯一应该阻止的地方是在 select() 调用内部。特别是,如果编码正确,服务器将永远不会在send()、recv() 或accept() 内部阻塞。最好将所有套接字设置为非阻塞模式(通过 fcntl(fd, F_SETFL, O_NONBLOCK))以保证此行为。
鉴于此,“在任何特定事件循环迭代中首先获得服务的客户端”的精确顺序并不重要,因为所有客户端的套接字在准备好数据(或准备好缓冲区空间)后很快就会得到处理-write),所有新连接都会很快被接受。
The server pattern shown in the example you linked to is fine; there isn't any significant problem introduced by the loop only accepting one socket per iteration.
The key point to keep in mind is that in a well-designed select() loop, the only place the process should ever block is inside the select() call. In particular, if coded correctly, the server will never block inside send(), recv(), or accept(). It's best to set all sockets to non-blocking mode (via fcntl(fd, F_SETFL, O_NONBLOCK)) in order to guarantee this behavior.
Given that, the precise ordering of "which clients get serviced first within any particular event loop iteration" doesn't matter, because all clients' sockets get handled very soon after they have data ready-for-read (or buffer space ready-for-write), and all new connections get accepted quickly.
select() 让程序员决定如何处理通知。对 select() 的一次调用可以指示任何或所有套接字都有要读取的字节以及要处理的一些连接请求。应用程序可以在调用 select() 之前处理所有通知,也可以在再次调用 select() 之前处理一个通知。
select() leaves it up to the programmer to decide how to handle notifications. One call to select() can indicate that any or all sockets have bytes to be read and some connection requests to process. The application can process all the notifications before calling select() or process one notification before calling select() again.