epoll相對於select、poll效能優越相當之多,可以說是二者結合加強版本,我們可以設想一下,假如有100w個tcp連線,那麼每次有資料過來了,select、poll都需要去從第乙個到最後乙個進行依次遍歷,而epoll會講佇列排序講發生事件放在前面,後面的就不用遍歷了,所以準確的說處理幾千的連線可以用select、poll但是太多了就不行,而且select、poll都是從使用者態拷貝到核心態,需要花費大量的時間,這樣比較起來epoll效能就相當的高了。
struct eventpoll
;
我們在呼叫epoll_create時,核心除了幫我們在epoll檔案系統裡建了個file結點,在核心cache裡建了個紅黑樹用於儲存以後epoll_ctl傳來的socket外,還會再建立乙個rdllist雙向鍊錶,用於儲存準備就緒的事件,當epoll_wait呼叫時,僅僅觀察這個rdllist雙向煉表裡有沒有資料即可。有資料就返回,沒有資料就sleep,等到timeout時間到後即使鍊錶沒資料也返回。所以,epoll_wait非常高效。
如果rdllist鍊錶不為空,則這裡的事件複製到使用者態記憶體(使用共享記憶體提高效率)中,同時將事件數量返回給使用者。因此epoll_waitx效率非常高。epoll_ctl在向epoll物件中新增、修改、刪除事件時,從rbr紅黑樹中查詢事件也非常快,也就是說epoll是非常高效的,它可以輕易地處理百萬級別的併發連線。
#include
intepoll_ctl
(int epfd,
int op,
int fd,
struct epoll_event *ev)
;
系統呼叫epoll_ctl()能夠修改由檔案描述符epfd所代表的epoll例項中的興趣列表。若成功返回0,若出錯返回-1。
第乙個引數epfd是epoll_create()的返回值; 第二個引數op用來指定需要執行的操作,它可以是如下幾種值:
epoll_ctl_add:將描述符fd新增到epoll例項中的興趣列表中去。對於fd上我們感興趣的事件,都指定在ev所指向的 結構體中。如果我們試圖向興趣列表中新增乙個已存在的檔案描述符,epoll_ctl()將出現eexist錯誤;
epoll_ctl_mod:修改描述符上設定的事件,需要用到由ev所指向的結構體中的資訊。如果我們試圖修改不在興趣列表 中的檔案描述符,epoll_ctl()將出現enoent錯誤;
poll_ctl_del:將檔案描述符fd從epfd的興趣列表中移除,該操作忽略引數ev。如果我們試圖移除乙個不在epfd的興 趣列表中的檔案描述符,epoll_ctl()將出現enoent錯誤。關閉乙個檔案描述符會自動將其從所有的epoll例項的興趣列表 移除;
第三個引數fd指明了要修改興趣列表中的哪乙個檔案描述符的設定。該引數可以是代表管道、fifo、套接字、posix訊息隊 列、inotify例項、終端、裝置,甚至是另乙個epoll例項的檔案描述符。但是,這裡fd不能作為普通檔案或目錄的檔案描述符;
第四個引數ev是指向結構體epoll_event的指標,結構體的定義如下:
typedef
union epoll_data epoll_data_t;
struct epoll_event
;
#include
#include
#include
#include
#include
#include
#include
#include
#include
void
handler_events
(int epfd,
struct epoll_event revs,
int num,
int listen_sock)
printf
("get a new link![%s:%d]\n"
,inet_ntoa
(client.sin_addr)
,ntohs
(client.sin_port));
//因為只是乙個http協議:連線成功後,下面就是要 請求和響應
// 而伺服器端響應之前:要先去讀客戶端要請求的內容
ev.events = epollin;
ev.data.fd = new_sock;
epoll_ctl
(epfd,epoll_ctl_add,new_sock,
&ev)
;continue;}
// 如果是普通檔案描述符,則呼叫read提供讀取資料的服務
if(revs[i]
.events & epollin)
else
if( s ==0)
else
// s = -1 失敗了
continue;}
// 伺服器端給客戶端響應: 寫
if( revs[i]
.events & epollout )}}
intstartup
(int port )
// 2. 解決time_wait時,伺服器不能重啟問題;使伺服器可以立即重啟
int opt =1;
setsockopt
(sock,sol_socket,so_reuseaddr,
&opt,
sizeof
(opt));
struct sockaddr_in local;
local.sin_family = af_inet;
local.sin_addr.s_addr =
htonl
(inaddr_any)
;// 位址為任意型別
local.sin_port =
htons
(port)
;// 這裡的埠號也可以直接指定8080
// 3. 繫結埠號if(
bind
(sock,
(struct sockaddr *
)&local,
sizeof
(local)
)<0)
// 4. 獲得監聽套接字if(
listen
(sock,5)
<0)
return sock;
}int
main
(int argc,
char
* ar**)
// 2. 獲得監聽套接字
int listen_sock =
startup
(atoi
("8899"))
;//埠號傳入的時候是以字串的形式傳入的,需要將其轉為整型
// 3. 初始化結構體----監聽的結構列表
struct epoll_event ev;
ev.events = epollin;
//關心讀事件
ev.data.fd = listen_sock;
// 關心的描述檔案描述符
// 4. epoll的事件註冊函式---新增要關心的檔案描述符的唯讀事件
epoll_ctl
(epfd,epoll_ctl_add,listen_sock,
&ev)
;struct epoll_event revs[
128]
;int n =
sizeof
(revs)
/sizeof
(revs[0]
);int timeout =
3000
;int num =0;
while(1
)}close
(epfd)
;close
(listen_sock)
;return0;
}
epoll多路復用
1 基本知識 epoll是在2.6核心中提出的,是之前的select和poll的增強版本。相對於select和poll來說,epoll更加靈活,沒有描述符限制。epoll使用乙個檔案描述符管理多個描述符,將使用者關係的檔案描述符的事件存放到核心的乙個事件表中,這樣在使用者空間和核心空間的copy只需...
多路復用 epoll
這是乙個基於epoll多路復用的服務端 include include include include include include include include include includeint recv data int fd,char buff else if errno eintr ...
select多路復用壓力測試
1 shell指令碼 bin bash bin bash for i 1 i 1100 i i 1 do.a echo i sleep 0.005 done echo 8 cat test.log grep f wc l cat test.log grep o wc l echo 2 客戶端 inc...