type
status
date
slug
summary
tags
category
icon
password
上一章,我们讲解了select I/O 多路复用技术。它通过三个不同的文件描述符集合来表示不同的 I/O 事件:可读、可写和异常。但select有一个缺点,那就是所支持的文件描述符的个数是有限的;在 Linux 系统中,select所支持的文件描述符的最大值默认为 1024。
那有没有别的 I/O 多路复用技术可以突破文件描述符个数的限制呢?当然有,poll就是其中一种方式。

1. poll()

select()相比,poll()和内核交互的数据结构有所变化。poll()函数的原型如下:
参数说明
fds: fds是一个struct pollfd数组。表示要监视的文件描述符集合,以及应用程序对每个文件描述符感兴趣的事件。
nfds: fds数组的长度。
timeout: 超时时间,精度为毫秒。负数表示无限期阻塞;0 表示不阻塞,立马返回。
其中,struct pollfd结构体的定义如下:
这个结构体有三个成员:
  • fd是文件描述符。
  • events表示应用程序感兴趣的事件类型。常见的事件类型有:POLLINPOLLOUT,分别表示读事件和写事件,它们之间可以进行按位或。
  • revents表示“returned events”,已发生了哪些事件。revents里除了可以包含POLLINPOLLOUT外,还可以包含POLLERRPOLLHUPPOLLNVAL,表示发生了某种类型的错误。注意,POLLERRPOLLHUPPOLLNVALevents中指定是没有效果的。(man 2 poll)
poll()函数有一点设计地非常好:如果我们不想对某个struct pollfd进行检测,只要将它的fd成员设置成负数即可。这样,内核将忽略这个结构体的events成员,待检测完毕之后,对应的revents的值将被设为 0。
📢
select vs poll 使用select()时,文件描述符的上限是由fd_set的实现决定的,我们没办法进行修改;而在poll()里,监视文件描述符的个数是由struct pollfd数组的长度决定的,而数组是我们自己申请的。

2. 经典案例——聊天室

接下来,我们使用poll()来构建一个多人聊天室服务器:
  • 准许多人同时进入聊天室,也允许任何人随时退出聊天室。
  • 发送的消息会同时转发给聊天室的其他成员。

总结归纳

这一章,我们讲了以下内容:
  • poll()——poll是另一种 I/O 多路复用的方式,它的性能和select相差无几。pollselect的区别在于:poll没有文件描述符上限的限制。
  • 最后,我们用poll重写了聊天室服务器的案例。希望通过这个案例,大家能熟练掌握poll()的用法。

参考文章

  • UNIX Network Programming, Volume 1: The Sockets Networking API, 3rd Edition
 
💡
欢迎您在底部评论区留言,我们一起交流学习~
高性能网络编程(8)——I/O 多路复用之 epoll高性能网络编程(6)——I/O 多路复用之 select