一、前言
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 | 自定義的服務端和客戶端程序 |