一、前言
Redis
网络库是一个单线程EPOLL
模型的网络库,和Memcached
使用的libevent
相比,它没有那么庞大,代码一共2000
多行,因此比较容易分析。其实网上已经有非常多有关这个网络库的分析了,但是我觉得它们的不足在于只是分析了各个文件中各个函数的单独含义,而没有将其统一起来,不能给读者一种宏观的把握。比如我如果想把这个网络库直接拿出来为我所用该怎么办,但是 @浅墨 学长已经完成了这个事,他拿出了Redis
网络部分的代码,设计了应用层协议,添加了应用层buffer
,定义了服务器类型。让它现在变成了一个可以实现简单聊天的小程序。 大家可以 fork
这个项目,在这个单线程的网络模型上做更多有意思的事情。
因此我的分析基于这个简单的聊天程序,我们从创建服务器开始,到它开始工作,把整个过程疏理一遍其实网络库主干就已经出来了,而且这种方式更加容易让人明白各个函数的真正含义,话不多说,撸起袖子开干。
二、环境准备
1:fork
&clone
$ git clone https://github.com/hurley25/ANet.git
2: 测试一波
$ cd ANet/
$ cmake .
$ make
$ ./server
$ ./server_test //在另一个终端
备注:客户端测试分为三次发送(每次20个数据包),第一次正常发送,第二次usleep(10000)
,第三次分为单个字节发送,服务器端结果显示均正常到达。TCP是一个流协议,保证按字节到达,应用层的粘包需要我们自己处理,这里是通过测试的。
三、模型介绍
Redis
网络库是一个单线程EPOLL
模型,也就是说接收连接
和处理读写请求
包括定时器任务
都被这一个线程包揽,真的是又当爹又当妈,但是效率一定比多线程差吗?不见得。
单线程的好处有:
1:避免线程切换带来的上下文切换开销。
2:单线程避免了锁的争用。
3:对于一个内存型数据库,如果不考虑数据持久化,也就是读写物理磁盘,不会有阻塞操作,内存操作是非常快的。
它的处理流程如图所示:
四、各个文件含义介绍
各个文件的含义如下所示(前两行是Redis源码):
文件 | 作用 |
---|---|
ae.c ae.h ae_epoll.c ae_select.c | Redis事件处理器的实现,Linux平台上是epoll(Redis源码) |
anet.c anet.h | Redis网络库的实现(Redis源码) |
buffer.c buffer.h | 自行实现的buffer |
protocol.c protocol.h | 自行定义协议 |
define.h | 一些常量,比如listen的backlog大小 |
server.c server.h server_test.c | 自定义的服务端和客户端程序 |