网络编程实战
盛延敏
前大众点评云平台首席架构师
立即订阅
6034 人已学习
课程目录
已完结 39 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | 学好网络编程,需要掌握哪些核心问题?
免费
第一模块:基础篇 (9讲)
01 | 追古溯源:TCP/IP和Linux是如何改变世界的?
02 | 网络编程模型:认识客户端-服务器网络模型的基本概念
03丨套接字和地址:像电话和电话号码一样理解它们
04 | TCP三次握手:怎么使用套接字格式建立连接?
05 | 使用套接字进行读写:开始交流吧
06 | 嗨,别忘了UDP这个小兄弟
07 | What? 还有本地套接字?
08 | 工欲善其事必先利其器:学会使用各种工具
09丨答疑篇:学习网络编程前,需要准备哪些东西?
第二模块:提高篇 (10讲)
10 | TIME_WAIT:隐藏在细节下的魔鬼
11 | 优雅地关闭还是粗暴地关闭 ?
12 | 连接无效:使用Keep-Alive还是应用心跳来检测?
13 | 小数据包应对之策:理解TCP协议中的动态数据传输
14丨UDP也可以是“已连接”?
15 | 怎么老是出现“地址已经被使用”?
16 | 如何理解TCP的“流”?
17 | TCP并不总是“可靠”的?
18 | 防人之心不可无:检查数据的有效性
19丨提高篇答疑:如何理解TCP四次挥手?
期中复习周 (2讲)
期中大作业丨动手编写一个自己的程序吧!
免费
期中大作业丨题目以及解答剖析
免费
第三模块:性能篇 (12讲)
20 | 大名⿍⿍的select:看我如何同时感知多个I/O事件
21 | poll:另一种I/O多路复用
22 | 非阻塞I/O:提升性能的加速器
23 | Linux利器:epoll的前世今生
24 | C10K问题:高并发模型设计
25 | 使用阻塞I/O和进程模型:最传统的方式
26 | 使用阻塞I/O和线程模型:换一种轻量的方式
27 | I/O多路复用遇上线程:使用poll单线程处理所有I/O事件
28 | I/O多路复用进阶:子线程使用poll处理连接I/O事件
29 | 渐入佳境:使用epoll和多线程模型
30 | 真正的大杀器:异步I/O探索
31丨性能篇答疑:epoll源码深度剖析
第四模块:实战篇 (4讲)
32 | 自己动手写高性能HTTP服务器(一):设计和思路
33 | 自己动手写高性能HTTP服务器(二):I/O模型和多线程模型实现
34 | 自己动手写高性能HTTP服务器(三):TCP字节流处理和HTTP协议实现
35 | 答疑:编写高性能网络编程框架时,都需要注意哪些问题?
结束语 (1讲)
结束语丨我相信这不是结束,让我们江湖再见
网络编程实战
登录|注册

21 | poll:另一种I/O多路复用

盛延敏 2019-09-25
你好,我是盛延敏,这是网络编程实战第 21 讲,欢迎回来。
上一讲我们讲到了 I/O 多路复用技术,并以 select 为核心,展示了 I/O 多路复用技术的能力。select 方法是多个 UNIX 平台支持的非常常见的 I/O 多路复用技术,它通过描述符集合来表示检测的 I/O 对象,通过三个不同的描述符集合来描述 I/O 事件 :可读、可写和异常。但是 select 有一个缺点,那就是所支持的文件描述符的个数是有限的。在 Linux 系统中,select 的默认最大值为 1024。
那么有没有别的 I/O 多路复用技术可以突破文件描述符个数限制呢?当然有,这就是 poll 函数。这一讲,我们就来学习一下另一种 I/O 多路复用的技术:poll。

poll 函数介绍

poll 是除了 select 之外,另一种普遍使用的 I/O 多路复用技术,和 select 相比,它和内核交互的数据结构有所变化,另外,也突破了文件描述符的个数限制。
下面是 poll 函数的原型:
int poll(struct pollfd *fds, unsigned long nfds, int timeout);
   
返回值:若有就绪描述符则为其数目,若超时则为0,若出错则为-1
这个函数里面输入了三个参数,第一个参数是一个 pollfd 的数组。其中 pollfd 的结构如下:
struct pollfd {
int fd; /* file descriptor */
short events; /* events to look for */
short revents; /* events returned */
};
这个结构体由三个部分组成,首先是描述符 fd,然后是描述符上待检测的事件类型 events,注意这里的 events 可以表示多个不同的事件,具体的实现可以通过使用二进制掩码位操作来完成,例如,POLLIN 和 POLLOUT 可以表示读和写事件。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《网络编程实战》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(17)

  • d
    老师可否简单讲下底层实现,比如底层是数组,队列,红黑树等。

    作者回复: 好问题,我收集一下素材。

    2019-09-25
    2
    5
  • 徐凯
    1.采用动态分配数组的方式
    2.如果内存不够 进行realloc 或者申请一块更大的内存 然后把源数组拷贝过来

    作者回复: 鼓励动手来一个。

    2019-09-25
    5
  • 夏目
    老师,我还是没明白poll和select的本质区别是什么,能否指点一下

    作者回复: 两者只是编程接口的区别,从内核实现角度来讲,其实本质实现是差不多的,poll客服了select有限文件描述字的缺陷,适用的范围更广一些。

    2019-11-15
    3
  • Hale
    能讲讲为什么不用POLLIN来判断套接字可读?

    作者回复: POLLIN包括了OOB等带外数据的检测,POLLRDNORM则不包括这部分。

    #define POLLIN 0x0001 /* any readable data available */
    #define POLLRDNORM 0x0040 /* non-OOB/URG data available */

    2019-09-26
    3
  • 阿卡牛
    还有种信号驱动型I/O,老师可以讲解吗

    作者回复: 让内核在描述符就绪时发送SIGIO信号通知我们,这种模型为信号驱动式I/O(signal-driven I/O),说实话,这个模型在实战中用的是比较少的,作为一个知识点知道就可以了。

    2019-10-24
    1
  • 传说中的成大大
    第一问: 我觉得需要改进的原因在于他是一个固定死了的值,而很多时候我们都要考虑到扩容的问题,所以可以把所有的描述符push_back到一个vector等类似的容器当中,直接对容器取size就可以获得数量
    第二问:把新连接上来的connfd添加进去,对上面问题的容器进行一次取size操作就行了
    通过前面两个问题 我产生了第三个问题
    我们都知道select 每次循环都需要向内核重新注册一次需要关心的描述符, 在Poll当中他是怎么处理的呢?也是每次都要注册一次吗?新增了描述放到集合当中肯定也需要通知内核啊 !

    作者回复: poll也是每次向内核注册了一个描述符集合,做法没有区别。你看到的这段代码,就是新增的描述符

        //找到一个可以记录该连接套接字的位置
                for (i = 1; i < INIT_SIZE; i++) {
                    if (event_set[i].fd < 0) {
                        event_set[i].fd = connected_fd;
                        event_set[i].events = POLLRDNORM;
                        break;
                    }
                }

    2019-09-30
    1
  • LDxy
    为什么程序里使用POLLRDNORM而不是POLLIN呢?这两者又何不同?

    作者回复: #define POLLRDNORM 0x0040 /* non-OOB/URG data available */
    #define POLLIN 0x0001 /* any readable data available */

    2019-09-25
    1
  • Geek_68d3d2
    老师我看网络编程里面使用了各种函数,函数里面各种参数,您那里有没有什么文档参考手册啥的可供我们需要时翻阅,光靠脑子记,记不来啊。您平常都是怎么写代码啊,这些函数都是背下来了吗。
    2019-12-11
  • godtrue
    poll 是另一种在各种 UNIX 系统上被广泛支持的 I/O 多路复用技术,虽然名声没有 select 那么响,能力一点不比 select 差,而且因为可以突破 select 文件描述符的个数限制,在高并发的场景下尤其占优势。

    老师好,之前听过IO多路复用存在一个使CPU飙升的问题,不知具体是哪个IO多路复用函数引起的,具体原因是什么,怎么解决的,老师能否介绍一下?

    作者回复: 你是在什么上下文理听过这个问题的呢?

    2019-11-24
    2
  • 贺荣伟
    认真多看几遍,老师讲解的很到位
    2019-11-21
  • ´◔ ‸◔)
    老师讲的真好,非常感谢。

    作者回复: 谢谢支持~。

    2019-10-31
  • 传说中的成大大
    我不太理解的是 之前好像理解到一个概念就是select每次轮训都会重新向内核注册需要关心的描述符这个缺点,那Poll呢?

    作者回复: poll也一样的,

    poll(event_set, INIT_SIZE, -1)),这个event_set就是每次轮询的事件全集。

    2019-09-30
  • 传说中的成大大
    我还是不太明白select和poll进行事件注册的区别,希望老师再给我指点指点

    作者回复: 区别是编程的接口不一样,原理基本一致,但是select一般来说有文件句柄的现在,poll则没有。我觉得你可以看代码体会一下。

    2019-09-30
  • Jimmy Xiong
    请问老师,例子的全代码(可以直接运行起来)哪里可以找得到?

    作者回复: https://github.com/froghui/yolanda

    2019-09-28
  • CCC
    > lsof -i:43211
    COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
    pollserve 56364 jinhaoplus 3u IPv4 0xd6b66f6bf4c36f21 0t0 TCP *:43211 (LISTEN)
    pollserve 56364 jinhaoplus 4u IPv4 0xd6b66f6bf3b80f21 0t0 TCP localhost:43211->localhost:63829 (ESTABLISHED)
    pollserve 56364 jinhaoplus 5u IPv4 0xd6b66f6bf49d05a1 0t0 TCP localhost:43211->localhost:63851 (ESTABLISHED)
    pollserve 56364 jinhaoplus 6u IPv4 0xd6b66f6bf427d921 0t0 TCP localhost:43211->localhost:63876 (ESTABLISHED)
    telnet 56379 jinhaoplus 5u IPv4 0xd6b66f6be79fc921 0t0 TCP localhost:63829->localhost:43211 (ESTABLISHED)
    telnet 56381 jinhaoplus 5u IPv4 0xd6b66f6be1866f21 0t0 TCP localhost:63851->localhost:43211 (ESTABLISHED)
    telnet 56529 jinhaoplus 5u IPv4 0xd6b66f6bf4944921 0t0 TCP localhost:63876->localhost:43211 (ESTABLISHED)

    我开启了三个telnet客户端连接这个pollserver,老师能否解释下上面的lsof命令中为什么客户端持有的FD是这样的情况呢?客户端持有的FD不应该是各自的connectfd嘛?

    作者回复: 63829,63851,63851就是三个不同的telnet客户端连接端口,由此断定肯定是三个不同的连接套接字。

    2019-09-26
  • 初见
    老师您好~

    我们既然有了poll,是不是代表着select 可以废弃了呢?

    还是说他们各自仍然有不同的使用场景?

    作者回复: 场景不同,select仍然活跃在各种场合。

    2019-09-25
  • 安排
    fd可读事件是不是有可能会误触发?也就是fd发生了可读事件,但是实际上并没有数据可读? 所以我们要用非阻塞的读。 这是内核的一个bug吗?还是。。。

    作者回复: 你是说使用阻塞I/O配合poll来使用?

    2019-09-25
    1
收起评论
17
返回
顶部