网络编程实战
盛延敏
前大众点评云平台首席架构师
立即订阅
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讲)
结束语丨我相信这不是结束,让我们江湖再见
网络编程实战
登录|注册

27 | I/O多路复用遇上线程:使用poll单线程处理所有I/O事件

盛延敏 2019-10-09
你好,我是盛延敏,这里是网络编程实战第 27 讲,欢迎回来。
我在前面两讲里,分别使用了 fork 进程和 pthread 线程来处理多并发,这两种技术使用简单,但是性能却会随着并发数的上涨而快速下降,并不能满足极端高并发的需求。就像第 24 讲中讲到的一样,这个时候我们需要寻找更好的解决之道,这个解决之道基本的思想就是 I/O 事件分发。
关于文稿中的代码,你可以去GitHub上查看或下载完整代码。

重温事件驱动

基于事件的程序设计: GUI、Web

事件驱动的好处是占用资源少,效率高,可扩展性强,是支持高性能高并发的不二之选。
如果你熟悉 GUI 编程的话,你就会知道,GUI 设定了一系列的控件,如 Button、Label、文本框等,当我们设计基于控件的程序时,一般都会给 Button 的点击安排一个函数,类似这样:
//按钮点击的事件处理
void onButtonClick(){
}
这个设计的思想是,一个无限循环的事件分发线程在后台运行,一旦用户在界面上产生了某种操作,例如点击了某个 Button,或者点击了某个文本框,一个事件会被产生并放置到事件队列中,这个事件会有一个类似前面的 onButtonClick 回调函数。事件分发线程的任务,就是为每个发生的事件找到对应的事件回调函数并执行它。这样,一个基于事件驱动的 GUI 程序就可以完美地工作了。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《网络编程实战》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(21)

  • 贺荣伟
    这篇文章,多了很多生动的图片,感觉干货满满啊,哈哈,希望后面的课程,也能多加点对应的图片就更好了。

    作者回复: 我想应该是可以满足你的要求的:)

    2019-10-24
    1
  • 徐凯
    我看到别人的代码用到了老师说的这个思想,在接收消息它采用的是分发订阅模式 通过订阅者的回调来接收消息 没有特定的recv接口露给外界 这种设计思想老师怎么看

    作者回复: 这是框架设计的基本思想,我在后面的框架设计中也是这样的,欢迎继续阅读,你会有更多收获。

    2019-10-22
    1
  • 传说中的成大大
    之前由于忙着买房子 落下了很多课程 现在都在追,不过不管是追还是慢慢跟 我都会再好好复习的

    作者回复: 加油~

    2019-10-15
    1
    1
  • fxzhang
    老师可否讲解linux下如何开发的,最近想换工作,但是之前都在windows下面开发,想自学一下linux下是如何开发的,但是有一种找不到开头不知道该怎么学习的感觉,很无力

    作者回复: 先学习一下Linux下的安装、配置、管理,把工作环境放到Linux下面,让Linux成为你的工作效率机器;

    其次,慢慢学习Bash,感受一下Linux的能力;

    接下来就是学习一些 Linux下的程序设计,如I/O、网络等。

    如果你能把这篇系列的所有代码都改一遍,运行一遍,就是一个良好的开头。

    加油~

    2019-10-09
    1
  • 林林
    worker thread 和 reactor thread之间怎么进行数据传递?是要利用队列+锁吗?

    作者回复: 这就是两个普通的producer-consumer线程关系,使用队列+锁的方式是一个比较常见的实现方式。

    2019-11-26
  • godtrue
    1:事件驱动模型的设计思想是啥?
    事件驱动模型的设计的思想是,一个无限循环的事件分发线程在后台运行,一旦做了某种操作触发了一个事件,这个事件就会被放置到事件队列中,事件分发线程的任务,就为这个发生的事件找到对应的事件回调函数并执行它。
    这里有个疑问,事件分发线程怎么找到事件的回调函数,并调用它的?

    2:事件驱动模型的优势是啥?
    事件驱动的好处是占用资源少,效率高,可扩展性强,是支持高性能高并发的不二之选。
    老师好,请问占用资源少这个结论是怎么得出来的?

    3:IO网络通信是怎么实现事件驱动模型的?
    通过使用 poll、epoll 等 I/O 分发技术,可以设计出基于套接字的事件驱动程序,从而满足高性能、高并发的需求。

    4:Reactor模型是啥玩意?
    Reactor模型(中文叫做反应堆模型)也就是事件驱动模型或者是 Event loop 模型。
    这个模型的核心有两点。
    第一,它存在一个无限循环的事件分发线程,或者叫做 reactor 线程、Event loop 线程。这个事件分发线程的背后,就是 poll、epoll 等 I/O 分发技术的使用。
    第二,所有的 I/O 操作都可以抽象成事件,每个事件必须有回调函数来处理。acceptor 上有连接建立成功、已连接套接字上发送缓冲区空出可以写、通信管道 pipe 上有数据可以读,这些都是一个个事件,通过事件分发,这些事件都可以一一被检测,并调用对应的回调函数加以处理。
    5:Reactor模型——解决了空闲连接占用资源的问题,Reactor线程只负责处理 I/O 相关的工作,业务逻辑相关的工作都被裁剪成一个一个的小任务,放到线程池里由空闲的线程来执行。当结果完成后,再交给反应堆线程,由Reactor线程通过套接字将结果发送出去。
    所以,这个模式性能更优。

    6:阻塞IO+多进程——实现简单,性能一般
    7:阻塞IO+多线程——相比于阻塞IO+多进程,减少了上下文切换所带来的开销,性能有所提高。
    8:阻塞IO+线程池——相比于阻塞IO+多线程,减少了线程频繁创建和销毁的开销,性能有了进一步的提高。
    9:Reactor+线程池——相比于阻塞IO+线程池,采用了更加先进的事件驱动设计思想,资源占用少、效率高、扩展性强,是支持高性能高并发场景的利器。

    作者回复: 第一个问题,回调函数和套接字对应的,通过套接字找到对应的回调函数;

    第二个问题,因为是事件驱动,不需要分配固定的资源,仅仅使用几个线程就可以支持上万的连接,每个线程的利用率得到了最大提升。

    2019-11-24
  • 阿卡牛
    使用多线程有线程池,使用多进程有进程池吗?

    作者回复: 没有。

    2019-11-19
  • LIFE__MM
    https://github.com/froghui/yolanda/issues/8
    这个问题是运行服务器程序成功后,开启第一个客户端时报错Segmentation fault (core dumped),我通过GDB找出来dump原因,但是第一次遇到这样的问题不知道如何解决,希望老师帮助一下,谢谢!

    作者回复: github上回复了。

    2019-11-04
  • LIFE__MM
    https://github.com/froghui/yolanda/issues/8
    这是我在写完所有源文件后cmake make 收到的警告,一直无法解决,希望老师可以帮助一下,谢谢

    作者回复: 需要加入pthread这个lib。

    参考 lib/CMakeLists.txt下面的这段:
    target_link_libraries(yolanda pthread)

    2019-10-31
  • yusuf
    https://github.com/linuxxiaoyu/chap-27-homework

    作者回复: 赞赞赞。

    2019-10-28
  • LIFE__MM
    老师你好,最近学习libevent1.4版本的源码,想要依照源码写出一个简单的模型,但是遇到了很多问题,正好看到了您的课程就订阅了。请老师指导一下如何学习libevent源码并且造轮子写出一个简单的模型,我已经根据老师的课程已经开始仿照源码写出反应堆模型,但是对比libevent源码,感觉还是不太搞得定... 谢谢老师

    作者回复: 我这里的版本比libevent要简单许多,在这个基础上你可以再拿一些libevent的功能来,读懂libevent是需要花一点时间的

    2019-10-27
  • 传说中的成大大
    可能是我的环境设置问题
    2019-10-16
  • 传说中的成大大
    我把代码从git上拉下来过后 第一行的#include <lib/acceptor.h>应该改为#include"lib/acceptor.h"

    作者回复: 整一个MR来。

    2019-10-16
  • 传说中的成大大
    第二问根据工作中遇到的情况来看decode-compute-encode应该是业务逻辑,应该是工作线程上处理,觉得处理方式是每个描述符和每个线程做一个映射,并且注册一个回调函数,用这个函数来处理套接字收到消息事件,然后再执行decode-compute-encode逻辑
    2019-10-15
  • 传说中的成大大
    第一遍看完这篇文章 我就感受颇深 尤其是事件触发 这个模式 然后就想到工作当中的用到的skynet框架底层就是采用事件驱动,某个服务有数据达到 就去触发对应的服务,然后再回想工作当中很多逻辑都抽象成事件,通过一个主循环检测时间然后来触发对应的事件!
    更重要的一点,专栏下的代码我全部是自己手动实现了一遍 还用上了gdb很开心 很满足
    第27讲和第24讲 应该重点学习,这两讲都是很重要的理论基础

    作者回复: 你是问题最多的,我想也是收获最大的。

    调试、调试、调试,重要的问题讲三遍 :)

    2019-10-15
  • Berry Wang
    “文稿中的这张图很好地解释了这个设计模式,可想而知的是,随着客户数的变多,fork 的子进程也越来越多,即使客户和服务器之间的交互比较少,这样的子进程也不能被销毁,一直需要存在。” 老师这里的子进程需要一直存在是为什么呢?

    作者回复: 因为如果客户不把TCP连接tear down掉,我们也不知道什么时候会继续进行数据的发送,有可能每隔2分钟发送一个heartbeat包,也是可能的。

    2019-10-12
    1
  • 向东
    老师能否对事件分发调用event_loop的event_activate方法执行callback的部分涉及回调部分讲详细点呢?

    作者回复: 第四篇会详细进行分解讲述。

    2019-10-10
  • 星辰
    老师的代码 github上有 地址有同学已经发出来啦

    作者回复: 👍

    2019-10-09
    1
  • 沉淀的梦想
    onWriteCompleted是在什么情况被回调的呢?在整个测试中似乎都没有被回调

    作者回复: 写完成之后,你可以打印一段话看看是否被回调到。

    2019-10-09
  • 刘丹
    请问 lib 目录下的代码能贴出来给大家学习吗?

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

    2019-10-09
收起评论
21
返回
顶部