天天看點

Redis代碼閱讀3--Redis網絡監聽(1)



接下來的三篇文章将對Redis的網絡監聽流程及涉及到事件庫和各個主要方法進行介紹。

在介紹 redis的網絡監聽流程和事件庫之前,我們先設想一下,如果我們不采用

libevent

等流行的開源庫進行基于事件的網絡監聽,而是自己去實作一套基于事件的庫去進行網絡監聽,需要考慮些什麼,然後我們帶着這些問題去分析 Redis是如果通過少量的代碼來完成這個工作的。

在我認為,需要考慮的問題有以下一些(限于水準,暫時隻能想到這些

Redis代碼閱讀3--Redis網絡監聽(1)

):

1.  

采用何種 事件觸發機制 ,是 epoll, select, kquque,抑或 3種都支援

2.  

支援那些事件?

3.  

如何管理各種事件(資料結構 —響應,查找)?

4.  

如何響應 I/O事件?是異步還是同步?是單線程響應還是多線程響應?

5.  

如何盡快地響應各種事件?

Redis的作者沒有采用 libevent等之類的知名網絡庫,而是通過少量的代碼實作了一個基于反轉模式的輕量級網絡庫,對于這一點, Redis的作者是這樣解釋的,因為他覺得 libevent之類的知名網絡庫太過于龐大,而對 Redis來說隻需要異步監聽的基本功能,是以他不想引入過于“龐大”的第三庫。

首先我們從 ae.h檔案開始,介紹一下 redis網絡監聽所涉及的幾個結構體和方法

C代碼

Redis代碼閱讀3--Redis網絡監聽(1)
Redis代碼閱讀3--Redis網絡監聽(1)
Redis代碼閱讀3--Redis網絡監聽(1)

  1. /* A fired event */  
  2. typedef struct aeFiredEvent {  
  3.     int fd;  
  4.     int mask;  
  5. } aeFiredEvent;  
  6. /* State of an event based program */  
  7. typedef struct aeEventLoop {  
  8.     int maxfd;  
  9.     long long timeEventNextId;  
  10.     aeFileEvent events[AE_SETSIZE]; /* Registered events */  
  11.     aeFiredEvent fired[AE_SETSIZE]; /* Fired events */  
  12.     aeTimeEvent *timeEventHead;  
  13.     int stop;  
  14.     void *apidata; /* This is used for polling API specific data */  
  15.     aeBeforeSleepProc *beforesleep;  
  16. } aeEventLoop;  
/* A fired event */
typedef struct aeFiredEvent {
    int fd;
    int mask;
} aeFiredEvent;

/* State of an event based program */
typedef struct aeEventLoop {
    int maxfd;
    long long timeEventNextId;
    aeFileEvent events[AE_SETSIZE]; /* Registered events */
    aeFiredEvent fired[AE_SETSIZE]; /* Fired events */
    aeTimeEvent *timeEventHead;
    int stop;
    void *apidata; /* This is used for polling API specific data */
    aeBeforeSleepProc *beforesleep;
} aeEventLoop;
      
aeEventLoop

是用于網絡循環監聽一個結構體,其通過 events這個内部數組來維護要要監聽的檔案事件,通過 fired來維護 select到需要響應的檔案事件, timeEventHead則是把定時響應的時間事件通過連結清單的形式維護起來。

aeFileEvent是檔案讀寫事件的抽象

Redis代碼閱讀3--Redis網絡監聽(1)
Redis代碼閱讀3--Redis網絡監聽(1)
Redis代碼閱讀3--Redis網絡監聽(1)
  1. /* File event structure */  
  2. typedef struct aeFileEvent {  
  3.     int mask; /* one of AE_(READABLE|WRITABLE) */用來區分讀寫事件  
  4.     aeFileProc *rfileProc;   讀檔案事件的處理函數  
  5.     aeFileProc *wfileProc;  寫檔案事件的處理函數  
  6.     void *clientData;  
  7. } aeFileEvent;  
  8. aeTimeEvent則是定時響應的事件的抽象  
  9. /* Time event structure */  
  10. typedef struct aeTimeEvent {  
  11.     long long id; /* time event identifier. */  
  12.     long when_sec; /* seconds */  事件響應點的秒時刻  
  13.     long when_ms; /* milliseconds */事件響應的毫秒時刻  
  14.     aeTimeProc *timeProc;  事件響應函數  
  15.     aeEventFinalizerProc *finalizerProc;  
  16.     struct aeTimeEvent *next;  下一個要響應的時間事件  
  17. } aeTimeEvent  
/* File event structure */
typedef struct aeFileEvent {
    int mask; /* one of AE_(READABLE|WRITABLE) */用來區分讀寫事件
    aeFileProc *rfileProc;   讀檔案事件的處理函數
    aeFileProc *wfileProc;  寫檔案事件的處理函數
    void *clientData;
} aeFileEvent;
aeTimeEvent則是定時響應的事件的抽象
/* Time event structure */
typedef struct aeTimeEvent {
    long long id; /* time event identifier. */
    long when_sec; /* seconds */  事件響應點的秒時刻
    long when_ms; /* milliseconds */事件響應的毫秒時刻
    aeTimeProc *timeProc;  事件響應函數
    aeEventFinalizerProc *finalizerProc;
    void *clientData;
    struct aeTimeEvent *next;  下一個要響應的時間事件
} aeTimeEvent      

在 Redis的網絡監控庫裡面,

、 aeFileEvent和 aeTimeEvent之間的關系是:

Redis代碼閱讀3--Redis網絡監聽(1)

在了解了 Redis基于事件驅動的網絡庫所涉及的三個基本元件後,我們來看一下 Redis的網絡監聽的基本流程:

Redis代碼閱讀3--Redis網絡監聽(1)
接下來下一篇文章将介紹整個流程涉及到的具體方法

繼續閱讀