1. 程式人生 > >multi-reactor伺服器模型的C++封裝類(libevent+多執行緒實現)

multi-reactor伺服器模型的C++封裝類(libevent+多執行緒實現)

最近在看memcached的原始碼,覺得它那種libevent+多執行緒的伺服器模型(multi-reactor)真的很不錯,我將這個模型封裝成一個C++類,根據我的簡單測試,這個模型的效率真的很不錯,歡迎大家試用。

這個類的使用方法很簡單(缺點是不太靈活),只要派生一個類,根據需要重寫以下這幾個虛擬函式就行了:

  1. //新建連線成功後,會呼叫該函式
  2. virtualvoid ConnectionEvent(Conn *conn) { }  
  3. //讀取完資料後,會呼叫該函式
  4. virtualvoid ReadEvent(Conn *conn) { }  
  5. //傳送完成功後,會呼叫該函式(因為串包的問題,所以並不是每次傳送完資料都會被呼叫)
  6. virtualvoid WriteEvent(Conn *conn) { }  
  7. //斷開連線(客戶自動斷開或異常斷開)後,會呼叫該函式
  8. virtualvoid CloseEvent(Conn *conn, short events) { }  


如果大家有什麼建議或意見,歡迎給我發郵件:[email protected]


上程式碼:

標頭檔案:MultiServer.h

  1. //MultiServer.h  
  2. #ifndef MULTISERVER_H_  
  3. #define MULTISERVER_H_  
  4. #include <stdio.h>  
  5. #include <stdlib.h>  
  6. #include <unistd.h>  
  7. #include <string.h>  
  8. #include <errno.h>  
  9. #include <signal.h>  
  10. #include <time.h>  
  11. #include <pthread.h>  
  12. #include <fcntl.h>  
  13. #include <assert.h>
  14. #include <event.h>  
  15. #include <event2/bufferevent.h>  
  16. #include <event2/buffer.h>  
  17. #include <event2/listener.h>  
  18. #include <event2/util.h>  
  19. #include <event2/event.h>  
  20. class MultiServer;    
  21. class Conn;    
  22. class ConnQueue;    
  23. struct LibeventThread;    
  24. //這個類一個連結串列的結點類,結點裡儲存各個連線的資訊,  
  25. //並提供了讀寫資料的介面  
  26. class Conn    
  27. {    
  28.     //此類只能由TcpBaseServer建立,  
  29.     //並由ConnQueue類管理  
  30.     friendclass ConnQueue;    
  31.     friendclass MultiServer;    
  32. private:    
  33.     constint m_fd;             //socket的ID  
  34.     evbuffer *m_ReadBuf;        //讀資料的緩衝區  
  35.     evbuffer *m_WriteBuf;       //寫資料的緩衝區  
  36.     Conn *m_Prev;               //前一個結點的指標  
  37.     Conn *m_Next;               //後一個結點的指標  
  38.     LibeventThread *m_Thread;    
  39.     Conn(int fd=0);    
  40.     ~Conn();    
  41. public:    
  42.     LibeventThread *GetThread() { return m_Thread; }    
  43.     int GetFd() { return m_fd; }    
  44.     //獲取可讀資料的長度  
  45.     int GetReadBufferLen()    
  46.     { return evbuffer_get_length(m_ReadBuf); }    
  47.     //從讀緩衝區中取出len個位元組的資料,存入buffer中,若不夠,則讀出所有資料  
  48.     //返回讀出資料的位元組數  
  49.     int GetReadBuffer(char *buffer, int len)    
  50.     { return evbuffer_remove(m_ReadBuf, buffer, len); }    
  51.     //從讀緩衝區中複製出len個位元組的資料,存入buffer中,若不夠,則複製出所有資料  
  52.     //返回複製出資料的位元組數  
  53.     //執行該操作後,資料還會留在緩衝區中,buffer中的資料只是原資料的副本  
  54.     int CopyReadBuffer(char *buffer, int len)    
  55.     { return evbuffer_copyout(m_ReadBuf, buffer, len); }    
  56.     //獲取可寫資料的長度  
  57.     int GetWriteBufferLen()    
  58.     { return evbuffer_get_length(m_WriteBuf); }    
  59.     //將資料加入寫緩衝區,準備傳送  
  60.     int AddToWriteBuffer(char *buffer, int len)    
  61.     { return evbuffer_add(m_WriteBuf, buffer, len); }    
  62.     //將讀緩衝區中的資料移動到寫緩衝區  
  63.     void MoveBufferData()    
  64.     { evbuffer_add_buffer(m_WriteBuf, m_ReadBuf); }    
  65. };    
  66. //帶頭尾結點的雙鏈表類,每個結點儲存一個連線的資料  
  67. class ConnQueue    
  68. {    
  69. private:    
  70.     Conn *m_head;    
  71.     Conn *m_tail;    
  72. public:    
  73.     ConnQueue();    
  74.     ~ConnQueue();    
  75.     Conn *InsertConn(int fd, LibeventThread *t);    
  76.     void DeleteConn(Conn *c);    
  77.     //void PrintQueue();  
  78. };    
  79. //每個子執行緒的執行緒資訊  
  80. struct LibeventThread    
  81. {    
  82.     pthread_t tid;              //執行緒的ID  
  83.     struct event_base *base;    //libevent的事件處理機  
  84.     struct event notifyEvent;   //監聽管理的事件機  
  85.     int notifyReceiveFd;        //管理的接收端  
  86.     int notifySendFd;           //管道的傳送端  
  87.     ConnQueue connectQueue;     //socket連線的連結串列  
  88.     //在libevent的事件處理中要用到很多回調函式,不能使用類隱含的this指標  
  89.     //所以用這樣方式將TcpBaseServer的類指標傳過去  
  90.     MultiServer *tcpConnect;  //TcpBaseServer類的指標  
  91. };    
  92. class MultiServer    
  93. {    
  94. private:  
  95.     staticconstint EXIT_CODE = -1;