多路復用模型之epoll

2021-08-11 06:58:22 字數 3379 閱讀 9738

作為多路復用io模型,epoll致力於解決select與poll設計缺陷以提公升系統併發能力。

(1) 併發效率不隨文句柄數上公升而線性下降:

epoll避免了select模型中對所有每次所有檔案描述符控制代碼輪詢。它的底層採用紅黑樹記錄所有檔案控制代碼,並將活躍的連線存放至鍊錶中,在處理io事件時,只需遍歷該鍊錶即可。

(2) mmap加速核心與使用者態拷貝:

無論select,poll還是epoll都需要核心把fd訊息通知給使用者空間,如何避免不必要的記憶體拷貝就很重要,在linux2.5版本之後,epoll運用mmap核心對映減少了一次核心態至使用者態檔案描述符拷貝。

(3)作業系統控制代碼限制:

select受限於程序開啟檔案描述符限制,雖然通過修改相應的巨集並重新編譯核心可以解決,但代價太大;epoll在這方面沒有明確限制,在1gb記憶體的機器上大約是10萬左右,這個數目和系統記憶體關係很大。

相應介面:

int epoll_create(int size); //建立epoll控制代碼,size並不限制控制代碼數目

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);//事件註冊函式

op引數:

a)epoll_ctl_add, 往事件表中註冊fd上的事件;

b)epoll_ctl_mod, 修改fd上註冊的事件;

c)epoll_ctl_del, 刪除fd上註冊的事件。

struct epoll_event

; typedef union epoll_data

epoll_data;

int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout); //等待檔案描述符就緒

**示例:

#include 

#include

#include

#include

#include

#include

#include

#include

#define backlog 1024

#define max_event 1024

#define epoll_size 16

#define port 9000

int epfd = -1;

int main()

while(1)

close(epfd);

return0;}

void error_handler(struct epoll_event *event_fd)

void request_handler(int client_fd)

char buf[64];

memset(buf, 0, sizeof(buf));

int len = -1;

if((len = read(client_fd, buf, sizeof(buf))) < 0)else

if(len == 0)else

}void connect_handler(int server_socket)

int client_fd;

struct sockaddr_in client_addr;

socklen_t len = sizeof(client_addr);

memset(&client_addr, 0, len);

if((client_fd = accept(server_socket, &client_addr,&len)) < 0)

printf("[%s:%d] connected\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));

set_nonblock(client_fd);

struct epoll_event event;

memset(&event, 0, sizeof(event));

event.data.fd = client_fd;

event.events = epollin;

if(epoll_ctl(epfd, epoll_ctl_add, client_fd, &event) < 0)

perror("epoll_ctl error");

}int epoll_init(int epoll_size, int op, int fd, struct epoll_event event)

if(epoll_ctl(epfd, op, fd, &event) < 0)

return epfd;

}int create_socket(struct sockaddr_in socket_addr, int backlog)

int on = 1;

setsockopt(server_socket, sol_socket, so_reuseaddr, &on, sizeof(on));

if(bind(server_socket, &socket_addr, sizeof(socket_addr)) < 0)

if(listen(server_socket, backlog) < 0)

return server_socket;

}void set_nonblock(int fd)

ret = ret | o_nonblock;

if(fcntl(fd, f_setfl,ret) < 0)

perror("fcntl set error");

}char *get_client_info(int client_fd)

客戶端**:

#include 

#include

#include

#include

#include

#define port 8080

int main()

connect(socket_fd, &client_addr, sizeof(client_addr));

char send_buf[64],recv_buf[64];

memset(send_buf, 0, sizeof(send_buf));

memset(recv_buf, 0, sizeof(recv_buf));

while(fgets(send_buf,sizeof(send_buf),stdin)!=null)

close(socket_fd);

return

0;}

執行效果圖:

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 ...

IO多路復用之epoll模型

基於select和poll輪詢方式的低效性,epoll為了解決這個不足,應運而生,epoll可以告訴伺服器到底是哪些事件就緒了,epoll返回乙個事件集合陣列,告訴我們是前多少個事件就緒了,這樣我們只需要遍歷就緒事件集就可以了。就像我們學生向老師提問的案例一樣,當有若干學生向老師舉手時,老師把這些學...