作為多路復用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返回乙個事件集合陣列,告訴我們是前多少個事件就緒了,這樣我們只需要遍歷就緒事件集就可以了。就像我們學生向老師提問的案例一樣,當有若干學生向老師舉手時,老師把這些學...