32 | 自己动手写高性能HTTP服务器(一):设计和思路
该思维导图由 AI 生成,仅供参考
设计需求
- 深入了解
- 翻译
- 解释
- 总结
这篇文章深入介绍了设计和构建高性能HTTP服务器的关键技术和设计思路。首先,文章讨论了构建高性能网络编程框架的需求,包括采用reactor模型、支持多线程和封装读写操作到Buffer对象中。接着,详细介绍了反应堆模式设计、I/O模型和多线程模型设计,涉及到event_loop、channel、acceptor、event_dispatcher和channel_map等对象的设计和作用。文章重点分析了event_loop的运行和event_dispatcher的实现,以及channel对象的设计和作用。此外,还提供了思考题,鼓励读者深入思考和交流。 总的来说,这篇文章为读者提供了宝贵的参考和指导,使他们能够快速了解构建高性能HTTP服务器所需的关键技术和设计思路。同时,文章还提供了进一步深入学习的思考题,为读者提供了更多的交流和学习机会。
《网络编程实战》,新⼈⾸单¥59
全部留言(30)
- 最新
- 精选
- 吴小智map_make_space() 函数里 realloc() 和 memset() 两个函数用的很巧妙啊,realloc() 用来扩容,且把旧的内容搬过去,memset() 用来给新申请的内存赋 0 值。赞,C 语言太强大了。
作者回复: 显然是看进去了。
2019-10-2227 - LDxyevent_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-217 - 酸葡萄老师你好,问个基础的问题: 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-0123 - 沉淀的梦想看到map_make_space里面的realloc函数,突然有个疑问,既然操作系统底层支持直接在原数组上扩充内存,为什么Java不支持直接在原数组上扩容呢,ArrayList每次扩容都要重新拷贝一份原来的数据。
作者回复: 好问题,我试着解读一下: 第一,Java有JVM实现,在Java的世界里,它的对象是统一被JVM管理的,包括GC,对象管理,基于这一层考虑,它不可能使用系统级别的对象内存管理,这两个没有办法调和,就像你举的例子,如果我们创建一个类似ReallocList对象,那么这个对象的内存管理完全不是JVM那套了; 第二,JVM是一个跨OS的实现,我不知道是否Windows也有类似realloc函数,这样就需要JVM做到跨OS的直接内存接管,这和Java的思想是不一致的。
2019-10-2232 - 凌空飞起的剪刀腿int map_make_space(struct channel_map *map, int slot, int msize) { if (map->nentries <= slot) { int nentries = map->nentries ? map->nentries : 32; void **tmp; while (nentries <= slot) nentries <<= 1; tmp = (void **) realloc(map->entries, nentries * msize); if (tmp == NULL) return (-1); memset(&tmp[map->nentries], 0, (nentries - map->nentries) * msize); map->nentries = nentries; map->entries = tmp; } return (0); } 老师,fd不一定是连续的吧,这样会浪费内存存储空间吧?
作者回复: 很好的问题。 第一,你可以看看实际分配的fd,大概会是什么样子; 第二,除了这个方法,你有别的更高效的方法吗?因为从fd来查找数据,需要非常的快; 我个人的判断,这点内存不算什么,因为我在设计这个结构时,大部分数据都是指针类型的。
2021-06-071 - 谁家内存泄露了老师好,请问您的代码中关于锁的使用,我想知道您关于每个loop都设计了一个锁,可是这几个mutex都是局部变量吧?他们的作用范围是什么样的呢?这里想不清楚,请指点一下!
作者回复: 所有的作用范围是全局的,而mutex锁看情况,有些是线程级别的,比如这里: pthread_mutex_lock(&eventLoopThread->mutex);
2021-04-121 - Steiner如果Channel是一个管道,他连接着哪两个对象?
作者回复: 连接着client端的套接字和server端的套接字。
2021-02-181 - 漠博嵩感觉就是仿照netty框架做的
作者回复: 还真不是。
2022-05-24 - 菜鸡第二个问题有点疑问。channel_map中元素的空间大小是与fd的值正相关的,而不是跟当前在线的连接数量正相关,这样做是不是有点浪费内存?比如经历了很多次连接、断开之后,fd返回的值比较大,而此时只有几个未断开的连接,那么channel_map有必要申请那么大的内存空间嘛?
作者回复: 还好吧,channel_map中的元素没几个字节,比起复杂的压缩算法,这点实在是微不足道。而且,你也没办法预测后面的连接情况,准备好一个上限比较大的fd存储空间,其实是效率比较高的。
2022-05-08 - 群书用sock对通知 唤醒会不会增加逻辑线程或主线程的系统调用次数 限制了吞吐量呢
作者回复: 不会。因为唤醒是kernel干的,只不过是多了一路I/O而已。
2021-11-12