小編的世界 優質文選 主機
字體大小:
2020年12月01日 -
:
閑聊代碼
工作進程的主循環代碼大概這樣:
while(!exit) { //如果沒有退出標志則循環
int ret = epoll_wait(epfd, events, max events, timeout);
if (ret < 0) {
//出錯處理
break;
}
//正常返回時的ret返回值是觸發的事件個數
int i;
for (i =0; i < ret; i ++) {
//遍曆處理所有的觸發事件
}
//處理到時間的定時器事件
}
像http之類的具體協議的處理,都是在事件的回調函數裏做的。
epoll_event的結構分兩個部分,一個是具體的epoll事件的標志,例如EPOLLIN表示讀,EPOLLOUT表示寫。
另一部分是用戶自定義的上下文數據的指針。各模塊的數據結構可以放在這個指針裏。
如下圖,可以把自定義數據結構掛在e->data.ptr裏,其中e為struct epoll_event類型的指針。
假設自定義的連接上下文結構是:
struct connection {
int fd; // socket文件描述符
int (*read)(struct connnection* c);
//讀數據的函數指針
int (*write)(struct connection* c);
//寫數據的函數指針
uint8_t* readbuf; //讀緩沖區
int readbuf_size; //當前讀緩沖區大小
uint8_t* writebuf; //寫緩沖區
int writebuf_size; //寫緩沖區大小
void* data; //下一級模塊的結構體
};
那麼工作進程worker的主循環while()裏,遍曆觸發的事件的for循環的處理就是:
for (i =0; i < ret; i++) {
struct epoll_event* e = &events;
struct connection * c = e->data.ptr;
int ret2 = c->read(c);
}
這只是示例代碼,nginx的這部分代碼還是比較複雜的。
最精簡的事件框架記得是redis自帶的libae,大概幾百行。
libevent框架則特別的複雜。