epoll,select,poll都是基於linux/unix的io復用技術。所謂io復用簡單來說就是讓核心來告知我們哪些檔案描述符讀或寫準備就緒。具體定義大家可以查閱各類書籍。
epoll相對於select和poll來說對核心資源的利用更高效,因為select和poll是需要將帶有檔案描述符的資料結構拷貝到核心,通知時再把就緒的檔案描述符從核心區拷貝到用區。而epoll使用共享記憶體儲存資料,與核心區共享檔案描述符。
除此之外,epoll遍歷檔案描述符是以紅黑樹遍歷,而select和poll是以線性表的形式遍歷。
/*
epoll使用步驟:
- 建立乙個epoll模型 -> 乙個函式
- 將需要檢測的檔案描述符新增到epoll模型中
- 開始使用epoll檢測檔案描述符的狀態
- 檢測到了狀態變化
- 判斷是不是監聽的fd
- accept接受連線, 得到新的通訊fd, 將其新增到epoll樹上
- 負判斷是不是通訊的fd
- read
- 返回值為0 -> 對方關閉連線
- 將這個fd從樹上刪除
- write
*/
函式:
// 建立乙個epoll模型
#include
intepoll_create
(int size)
; 引數:
- size: 保證其大於0即可, 沒有其他的實際意義
返回值:
是乙個檔案描述符, 理解為建立的epoll樹的根節點
// 對epoll樹操作函式, 新增節點/刪除節點/修改節點屬性
typedef
union epoll_data epoll_data_t;
struct epoll_event
;events事件的取值為三個巨集:
- epollin: 讀事件 -> 檢測是fd的讀緩衝區
- epollout: 寫事件 -> 檢測是fd的寫緩衝區
- epollerr: 異常 -> 檢測fd是否有異常
intepoll_ctl
(int epfd,
int op,
int fd,
struct epoll_event *event)
; 引數:
- epfd: epoll數的根節點, 通過 epoll_create
(int size)
; 得到的, 返回值
- op: 對檔案描述符的操作
epoll_ctl_add: 新增新節點
epoll_ctl_mod: 修改節點是屬性
epoll_ctl_del: 刪除現有的節點
- fd: 要操作的檔案描述符
- event: fd的屬性設定
- 如果是刪除操作, 這個引數指定為null即可
// 委託核心檢測epoll樹上的檔案描述符狀態
intepoll_wait
(int epfd,
struct epoll_event *events,
int maxevents,
int timeout)
; 引數:
- epfd: epoll數的根節點, 通過 epoll_create
(int size)
; 得到的, 返回值
- events: 傳出引數, 指向乙個陣列的位址, 儲存傳送變化的檔案描述符的資訊
- maxevents: 引數events元素的個數
- timeout: 阻塞的時長, 單位是毫秒, ms
-0: 直接返回
--1: 一直阻塞, 直到檢測的檔案描述符有狀態變化, 解除阻塞
->
0: 阻塞的毫秒數,
- 在阻塞期間如果檢測的檔案描述符有狀態變化, 解除阻塞
- 沒有變化, 時間到了解除阻塞
返回值:-1
: 失敗
>
0: 狀態有變化的檔案描述符的個數
**:
#include
#include
#include
#include
#include
#include
#include
intmain()
繫結本地的ip和埠
struct sockaddr_in server_addr;
server_addr.sin_family = af_inet;
server_addr.sin_port =
htons
(9999);
//主機序轉網路序
server_addr.sin_addr.s_addr = inaddr_any;
int ret =
bind
(lfd,
(struct sockaddr*
)&server_addr,
sizeof
(server_addr));
//注意第二引數要強制轉換為(struct socket*)型別
//3,監聽lfd
ret =
listen
(lfd,
128);if
(ret==-1
)//4.建立epoll樹
int epfd=
epoll_create(0
);//5.將監聽檔案描述符新增到epoll樹上
//一旦產生連線就會被核心檢測到,我們後面做處理
struct epoll_event lev;
lev.data.fd = lfd;
lev.events = epollin;
ret =
epoll_ctl
(epfd, epoll_ctl_add, lfd,
&lev);if
(ret==-1
)//6.建立epoll_event 結構體陣列
struct epoll_event epr[
100]
;int size =
sizeof
(epr)
/sizeof
(struct epoll_event)
;//7.開始迴圈檢測
while
(true)
else
;int len =
read
(epr[i]
.data.fd, buf,
sizeof
(buf));
//recv(epr[i].data.fd, buf, sizeof(buf), 0);也行
if(len>0)
else}}
}}
高併發伺服器(基於epoll)
本章節是用基本的linux unix基本函式編寫乙個完整的伺服器和客戶端例子,可在linux ubuntu 和unix freebsd 上執行,客戶端和服務端的功能如下 客戶端從標準輸入讀入一行,傳送到服務端 服務端從網路讀取一行,把小寫變為大寫,然後輸出到客戶端 客戶端收到服務端的響應,輸出這一行...
支援高併發的基於epoll的go伺服器模型
參照使用go編寫,基於epoll io復用模型,多協程同時監聽埠epoll,基於工作池,防止無限制協程個數 服務端 select 阻塞 func startepoll epoller,err mkepoll if err nil go start epoller for log.printf acc...
Epoll實現伺服器高併發
最近在做乙個關於高併發伺服器相關的專案需要用到非同步 非阻塞io通訊,實現高tcp併發。以下用epoll技術實現乙個簡單的tcp高併發伺服器,驗證無業務處理的情況下,epoll處理併發連線的數的效果。include include include include include include in...