multi-reactor伺服器模型的C++封裝類(libevent+多執行緒實現)
阿新 • • 發佈:2019-01-20
最近在看memcached的原始碼,覺得它那種libevent+多執行緒的伺服器模型(multi-reactor)真的很不錯,我將這個模型封裝成一個C++類,根據我的簡單測試,這個模型的效率真的很不錯,歡迎大家試用。
這個類的使用方法很簡單(缺點是不太靈活),只要派生一個類,根據需要重寫以下這幾個虛擬函式就行了:
- //新建連線成功後,會呼叫該函式
- virtualvoid ConnectionEvent(Conn *conn) { }
- //讀取完資料後,會呼叫該函式
- virtualvoid ReadEvent(Conn *conn) { }
-
//傳送完成功後,會呼叫該函式(因為串包的問題,所以並不是每次傳送完資料都會被呼叫)
- virtualvoid WriteEvent(Conn *conn) { }
- //斷開連線(客戶自動斷開或異常斷開)後,會呼叫該函式
- virtualvoid CloseEvent(Conn *conn, short events) { }
如果大家有什麼建議或意見,歡迎給我發郵件:[email protected]
上程式碼:
標頭檔案:MultiServer.h
- //MultiServer.h
- #ifndef MULTISERVER_H_
- #define MULTISERVER_H_
-
#include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <string.h>
- #include <errno.h>
- #include <signal.h>
- #include <time.h>
- #include <pthread.h>
- #include <fcntl.h>
- #include <assert.h>
- #include <event.h>
-
#include <event2/bufferevent.h>
- #include <event2/buffer.h>
- #include <event2/listener.h>
- #include <event2/util.h>
- #include <event2/event.h>
- class MultiServer;
- class Conn;
- class ConnQueue;
- struct LibeventThread;
- //這個類一個連結串列的結點類,結點裡儲存各個連線的資訊,
- //並提供了讀寫資料的介面
- class Conn
- {
- //此類只能由TcpBaseServer建立,
- //並由ConnQueue類管理
- friendclass ConnQueue;
- friendclass MultiServer;
- private:
- constint m_fd; //socket的ID
- evbuffer *m_ReadBuf; //讀資料的緩衝區
- evbuffer *m_WriteBuf; //寫資料的緩衝區
- Conn *m_Prev; //前一個結點的指標
- Conn *m_Next; //後一個結點的指標
- LibeventThread *m_Thread;
- Conn(int fd=0);
- ~Conn();
- public:
- LibeventThread *GetThread() { return m_Thread; }
- int GetFd() { return m_fd; }
- //獲取可讀資料的長度
- int GetReadBufferLen()
- { return evbuffer_get_length(m_ReadBuf); }
- //從讀緩衝區中取出len個位元組的資料,存入buffer中,若不夠,則讀出所有資料
- //返回讀出資料的位元組數
- int GetReadBuffer(char *buffer, int len)
- { return evbuffer_remove(m_ReadBuf, buffer, len); }
- //從讀緩衝區中複製出len個位元組的資料,存入buffer中,若不夠,則複製出所有資料
- //返回複製出資料的位元組數
- //執行該操作後,資料還會留在緩衝區中,buffer中的資料只是原資料的副本
- int CopyReadBuffer(char *buffer, int len)
- { return evbuffer_copyout(m_ReadBuf, buffer, len); }
- //獲取可寫資料的長度
- int GetWriteBufferLen()
- { return evbuffer_get_length(m_WriteBuf); }
- //將資料加入寫緩衝區,準備傳送
- int AddToWriteBuffer(char *buffer, int len)
- { return evbuffer_add(m_WriteBuf, buffer, len); }
- //將讀緩衝區中的資料移動到寫緩衝區
- void MoveBufferData()
- { evbuffer_add_buffer(m_WriteBuf, m_ReadBuf); }
- };
- //帶頭尾結點的雙鏈表類,每個結點儲存一個連線的資料
- class ConnQueue
- {
- private:
- Conn *m_head;
- Conn *m_tail;
- public:
- ConnQueue();
- ~ConnQueue();
- Conn *InsertConn(int fd, LibeventThread *t);
- void DeleteConn(Conn *c);
- //void PrintQueue();
- };
- //每個子執行緒的執行緒資訊
- struct LibeventThread
- {
- pthread_t tid; //執行緒的ID
- struct event_base *base; //libevent的事件處理機
- struct event notifyEvent; //監聽管理的事件機
- int notifyReceiveFd; //管理的接收端
- int notifySendFd; //管道的傳送端
- ConnQueue connectQueue; //socket連線的連結串列
- //在libevent的事件處理中要用到很多回調函式,不能使用類隱含的this指標
- //所以用這樣方式將TcpBaseServer的類指標傳過去
- MultiServer *tcpConnect; //TcpBaseServer類的指標
- };
- class MultiServer
- {
- private:
- staticconstint EXIT_CODE = -1;