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

32 | 自己动手写高性能HTTP服务器(一):设计和思路

盛延敏 2019-10-21
你好,我是盛延敏,这里是网络编程实战第 32 讲,欢迎回来。
从这一讲开始,我们进入实战篇,开启一个高性能 HTTP 服务器的编写之旅。
在开始编写高性能 HTTP 服务器之前,我们先要构建一个支持 TCP 的高性能网络编程框架,完成这个 TCP 高性能网络框架之后,再增加 HTTP 特性的支持就比较容易了,这样就可以很快开发出一个高性能的 HTTP 服务器程序。

设计需求

在第三个模块性能篇中,我们已经使用这个网络编程框架完成了多个应用程序的开发,这也等于对这个网络编程框架提出了编程接口方面的需求,综合之前的使用经验,这个 TCP 高性能网络框架需要满足的需求有以下三点。
第一,采用 reactor 模型,可以灵活使用 poll/epoll 作为事件分发实现。
第二,必须支持多线程,从而可以支持单线程单 reactor 模式,也可以支持多线程主 - 从 reactor 模式。可以将套接字上的 I/O 事件分离到多个线程上。
第三,封装读写操作到 Buffer 对象中。
按照这三个需求,正好可以把整体设计思路分成三块来讲解,分别包括反应堆模式设计、I/O 模型和多线程模型设计、数据读写封装和 buffer。今天我们主要讲一下主要的设计思路和数据结构,以及反应堆模式设计。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《网络编程实战》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(13)

  • 小智e
    map_make_space() 函数里 realloc() 和 memset() 两个函数用的很巧妙啊,realloc() 用来扩容,且把旧的内容搬过去,memset() 用来给新申请的内存赋 0 值。赞,C 语言太强大了。

    作者回复: 显然是看进去了。

    2019-10-22
    1
  • LDxy
    event_loop_handle_pending_add函数中,
    map->entries[fd] = calloc(1, sizeof(struct channel *));
    map->entries[fd] = channel;
    这两行都给map->entries[fd] 赋值,后一行不是覆盖上一行的赋值了么?有何用意?

    作者回复: 这块是我的疏忽,应该直接赋值的,可能是开始我撰写的时候channel对象的初始化放到了event_loop_handle_pending_add函数中,后来把channel对象的初始化重构到外面,这里忘记删掉了。

    已经更新文稿(待周一编辑更新)和github代码,感谢指正。

    2019-10-21
    1
  • 传说中的成大大
    第二道题 就是一个扩容啊 类似std的vector自动扩容 而且每次成倍的增长
    2019-10-21
    1
  • 小蚂蚁
    老师你好,问个基础的问题:
    epoll_dispatcher和poll_dispatcher都有,在添加,删除,更新事件时都有如下的逻辑,其中if条件中的判断怎么理解啊?
    if (channel1->events & EVENT_READ) {
            events = events | POLLRDNORM;
        }

        if (channel1->events & EVENT_WRITE) {
            events = events | POLLWRNORM;
        }

    作者回复: 这里是位与操作,举个例子,EVENT_READ可能为二进制的00000010,如果有可读事件发生,那么在这个位上的bit值一定位1,这样位与的结果就说明这个事件发生了。之所以采用位与,而不是位或,是因为只需要关心这一种类型的事件。

    2019-12-01
    1
  • Steiner
    请问channel里的fd也需要设置为非阻塞吗

    作者回复: channel里的fd是在有连接建立时创建好的,当然,也是被设置为非阻塞的,这里channle对象不需要关系fd的属性。

    2019-10-22
  • 沉淀的梦想
    看到map_make_space里面的realloc函数,突然有个疑问,既然操作系统底层支持直接在原数组上扩充内存,为什么Java不支持直接在原数组上扩容呢,ArrayList每次扩容都要重新拷贝一份原来的数据。

    作者回复: 好问题,我试着解读一下:
    第一,Java有JVM实现,在Java的世界里,它的对象是统一被JVM管理的,包括GC,对象管理,基于这一层考虑,它不可能使用系统级别的对象内存管理,这两个没有办法调和,就像你举的例子,如果我们创建一个类似ReallocList对象,那么这个对象的内存管理完全不是JVM那套了;

    第二,JVM是一个跨OS的实现,我不知道是否Windows也有类似realloc函数,这样就需要JVM做到跨OS的直接内存接管,这和Java的思想是不一致的。

    2019-10-22
    2
  • 传说中的成大大
    老师 你好 问你一个和课程沾点点边的关系的问题哈,虽然我晓得什么这样模式那样模式 但是还是不会设计 比如像老师为课程设计的框架 回调都是两层 为什么要这样设计我却不明白 有没有什么规范啥的可以指导一下 可能真的是没好好学过设计模式,既然现在都涉及到要自己动手一个服务器框架了 我也想解决设计这方面的问题,希望老师点播一下

    作者回复: 放到统一答疑里了。

    2019-10-21
  • 传说中的成大大
    而且新连接,创建的channel对象上的回调也应该是tcp_connection上的回调

    作者回复: 统一答疑中解释。

    2019-10-21
  • 传说中的成大大
    lib/tcp_connection.c最终是在lib/tcp_connection.c 第22行执行了应用层的readcallback函数执行 epoll-server-multithreads.c onMessage为什么要封装两次呢? 封装一个tcp_connection是为了隐藏读取字节流的实现吗,主要是套接字层? tcp_server层主要就是引用层的这样理解可以吗?

    作者回复: 统一答疑中解释。

    2019-10-21
  • 传说中的成大大
    今天仔细研读了老师的代码突然发现有两层回调
    1. epoll-server-multithreads.c里面写的有回调 并且赋给了tcp_server
    2. tcp_connection.c 实现了 handle_read handle_write 等等事件的回调 为什么要封装两层回调呢 我设计模式没怎么学过 希望老师指点哈

    作者回复: 统一答疑中解释。

    2019-10-21
  • 传说中的成大大
    epollDispatcherData->events = calloc(MAXEVENTS, sizeof(struct acceptor));
    这一行不太明白为什么要分配MAXEVENTS* sizeof( struct acceptor )这么多内存?我的关注点在sizeof(
    struct acceptor ),为什么取它的大小?

    作者回复: 笔误,已修复。

    2019-10-21
  • 鱼向北游
    老师的程序读了一遍,c版的netty,果然高手们的思路都是相通的

    作者回复: 是操作系统提供的能力就是这样,大家都这么发挥了。

    2019-10-21
  • 刘系
    第二课后题:当描述字大于channel_map的容量时,map_make_space会被调用。在map初始化时,容量为0,往map里写描述字时先给容量为32,如果描述字仍然大于等于32将会使容量右移一位,也就是描述字容量增加两倍再与要写入的描述字进行比较,直至容量大于要写入的描述字。然后使用realloc进行空间开辟,保留原有空间,扩展新空间。将新空间内存置0。最后更新map
    2019-10-21
    1
收起评论
13
返回
顶部