Linux網路程式設計——I/O複用函式之epoll
https://blog.csdn.net/lianghe_work/article/details/46544567
一、epoll概述
epoll 是在 2.6 核心中提出的,是之前的 select() 和 poll() 的增強版本。相對於 select() 和 poll() 來說,epoll 更加靈活,沒有描述符限制。epoll 使用一個檔案描述符管理多個描述符,將使用者關係的檔案描述符的事件存放到核心的一個事件表中,這樣在使用者空間和核心空間的 copy 只需一次。
二、epoll操作過程需要的四個介面函式
四介面函式分別是:
- int epoll_create
(int size);- int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
- int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
- int close(int epfd);
int epoll_create(int size);
功能:
該函式生成一個epoll專用的檔案描述符(其餘的介面函式一般都用使用這個專用的檔案描述符)
引數:
size: 用來告訴核心這個監聽的數目一共有多大,引數 size 並不是限制了 epoll 所能監聽的描述符最大個數,只是對核心初始分配內部資料結構的一個建議。自從 linux 2.6.8 之後,size 引數是被忽略的,也就是說可以填只有大於 0 的任意值
。需要注意的是,當建立好 epoll 控制代碼後,它就是會佔用一個 fd 值,在 linux 下如果檢視 /proc/ 程序 id/fd/,是能夠看到這個 fd 的,所以在使用完 epoll 後,必須呼叫 close() 關閉,否則可能導致 fd 被耗盡返回值:
成功:epoll 專用的檔案描述符
失敗:-1int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
功能:
epoll 的事件註冊函式,它不同於 select() 是在監聽事件時告訴核心要監聽什麼型別的事件,而是在這裡先註冊要監聽的事件型別
引數:
epfd: epoll 專用的檔案描述符,epoll_create()的返回值
op: 表示動作,用三個巨集來表示:
fd: 需要監聽的檔案描述符EPOLL_CTL_ADD:註冊新的 fd 到 epfd 中;
EPOLL_CTL_MOD:修改已經註冊的fd的監聽事件;
EPOLL_CTL_DEL:從 epfd 中刪除一個 fd;event: 告訴核心要監聽什麼事件,struct epoll_event 結構如下:
events 可以是以下幾個巨集的集合:
- // 儲存觸發事件的某個檔案描述符相關的資料(與具體使用方式有關)
- typedef union epoll_data {
- void *ptr;
- int fd;
- __uint32_t u32;
- __uint64_t u64;
- } epoll_data_t;
- // 感興趣的事件和被觸發的事件
- struct epoll_event {
- __uint32_t events; /* Epoll events */
- epoll_data_t data; /* User data variable */
- };
EPOLLIN :表示對應的檔案描述符可以讀(包括對端 SOCKET 正常關閉);
EPOLLOUT:表示對應的檔案描述符可以寫;
EPOLLPRI:表示對應的檔案描述符有緊急的資料可讀(這裡應該表示有帶外資料到來);
EPOLLERR:表示對應的檔案描述符發生錯誤;
EPOLLHUP:表示對應的檔案描述符被結束通話;
EPOLLET :將 EPOLL 設為邊緣觸發(Edge Triggered)模式,這是相對於水平觸發(Level Triggered)來說的。
EPOLLONESHOT:只監聽一次事件,當監聽完這次事件之後,如果還需要繼續監聽這個 socket 的話,需要再次把這個 socket 加入到 EPOLL 佇列裡
返回值:
成功:0
失敗:-1int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
功能:
等待事件的產生,收集在 epoll 監控的事件中已經發送的事件,類似於 select() 呼叫。
引數:
epfd: epoll 專用的檔案描述符,epoll_create()的返回值
events: 分配好的 epoll_event 結構體陣列,epoll 將會把發生的事件賦值到events 陣列中(events 不可以是空指標,核心只負責把資料複製到這個 events 陣列中,不會去幫助我們在使用者態中分配記憶體)。
maxevents: maxevents 告之核心這個 events 有多大 。
timeout: 超時時間,單位為毫秒,為 -1 時,函式為阻塞
返回值:
成功:返回需要處理的事件數目,如返回 0 表示已超時。
失敗:-1
epoll 對檔案描述符的操作有兩種模式:LT(level trigger)和 ET(edge trigger)。LT 模式是預設模式,LT 模式與 ET 模式的區別如下:
LT 模式:當 epoll_wait 檢測到描述符事件發生並將此事件通知應用程式,應用程式可以不立即處理該事件。下次呼叫 epoll_wait 時,會再次響應應用程式並通知此事件。
ET 模式:當 epoll_wait 檢測到描述符事件發生並將此事件通知應用程式,應用程式必須立即處理該事件。如果不處理,下次呼叫 epoll_wait 時,不會再次響應應用程式並通知此事件。
ET 模式在很大程度上減少了 epoll 事件被重複觸發的次數,因此效率要比 LT 模式高。epoll 工作在 ET 模式的時候,必須使用非阻塞套介面,以避免由於一個檔案控制代碼的阻塞讀/阻塞寫操作把處理多個檔案描述符的任務餓死
int close(int epfd);
在用完之後,記得用close()來關閉這個創建出來的epoll控制代碼
三、epoll示例:
接下來我們epoll實現udp同時收發資料
- int main(int argc,char *argv[])
- {
- int udpfd = 0;
- int ret = 0;
- struct sockaddr_in saddr;
- struct sockaddr_in caddr;
- bzero(&saddr,sizeof(saddr));
- saddr.sin_family = AF_INET;
- saddr.sin_port = htons(8000);
- saddr.sin_addr.s_addr = htonl(INADDR_ANY);
- bzero(&caddr,sizeof(caddr));
- caddr.sin_family = AF_INET;
- caddr.sin_port = htons(8000);
- //建立套接字
- if( (udpfd = socket(AF_INET,SOCK_DGRAM, 0)) < 0)
- {
- perror("socket error");
- exit(-1);
- }
- //套接字埠綁字
- if(bind(udpfd, (struct sockaddr*)&saddr, sizeof(saddr)) != 0)
- {
- perror("bind error");
- close(udpfd);
- exit(-1);
- }
- printf("input: \"sayto 192.168.220.X\" to sendmsg to somebody\033[32m\n");
- struct epoll_event event; // 告訴核心要監聽什麼事件
- struct epoll_event wait_event;
- int epfd = epoll_create(10); // 建立一個 epoll 的控制代碼,引數要大於 0, 沒有太大意義
- if( -1 == epfd ){
- perror ("epoll_create");
- return -1;
- }
- event.data.fd = 0; // 標準輸入
- event.events = EPOLLIN; // 表示對應的檔案描述符可以讀
- // 事件註冊函式,將標準輸入描述符 0 加入監聽事件
- ret = epoll_ctl(epfd, EPOLL_CTL_ADD, 0, &event);
- if(-1 == ret){
- perror("epoll_ctl");
- return -1;
- }
- event.data.fd = udpfd; // 有名管道
- event.events = EPOLLIN; // 表示對應的檔案描述符可以讀
- // 事件註冊函式,將有udp描述符udpfd 加入監聽事件
- ret = epoll_ctl(epfd, EPOLL_CTL_ADD, udpfd, &event);
- if(-1 == ret){
- perror("epoll_ctl");
- return -1;
- }
- while(1)
- {
- // 監視並等待多個檔案(標準輸入,udp套接字)描述符的屬性變化(是否可讀)
- // 沒有屬性變化,這個函式會阻塞,直到有變化才往下執行,這裡沒有設定超時
- ret = epoll_wait(epfd, &wait_event, 2, -1);
- write(1,"UdpQQ:",6);
- if(ret == -1){ // 出錯
- close(epfd);
- perror("epoll");
- }
- else if(ret > 0){ // 準備就緒的檔案描述符
- char buf[100] = {0};
- if( ( 0 == wait_event.data.fd )
- && ( EPOLLIN == wait_event.events & EPOLLIN ) ){ // 標準輸入
- fgets(buf, sizeof(buf), stdin);
- buf[strlen(buf) - 1] = '\0';
- if(strncmp(buf, "sayto", 5) == 0)
- {
- char ipbuf[16] = "";
- inet_pton(AF_INET, buf+6, &caddr.sin_addr);//給addr套接字地址再賦值.
- printf("\rsay to %s\n",inet_ntop(AF_INET,&caddr.sin_addr,ipbuf,sizeof(ipbuf)));
- continue;
- }
- else if(strcmp(buf, "exit")==0)
- {
- close(udpfd);
- exit(0);
- }
- sendto(udpfd, buf, strlen(buf),0,(struct sockaddr*)&caddr, sizeof(caddr));
- }
- else if( ( udpfd == wait_event.data.fd )
- && ( EPOLLIN == wait_event.events & EPOLLIN )){ //udp套接字
- struct sockaddr_in addr;
- char ipbuf[INET_ADDRSTRLEN] = "";
- socklen_t addrlen = sizeof(addr);
- bzero(&addr,sizeof(addr));
- recvfrom(udpfd, buf, 100, 0, (struct sockaddr*)&addr, &addrlen);
- printf("\r\033[31m[%s]:\033[32m%s\n",inet_ntop(AF_INET,&addr.sin_addr,ipbuf,sizeof(ipbuf)),buf);
- }
- }
- else if(0 == ret){ // 超時
- printf("time out\n");
- }
- }
- return 0;
- }
執行結果:
相關推薦
Linux網路程式設計——I/O複用函式之epoll
https://blog.csdn.net/lianghe_work/article/details/46544567一、epoll概述epoll 是在 2.6 核心中提出的,是之前的 select() 和 poll() 的增強版本。相對於 select() 和 poll()
Linux網路程式設計---I/O複用模型之epoll
Linux網路程式設計—I/O複用模型之epoll 1. epoll模型簡介 epoll是Linux多路服用IO介面select/poll的加強版,e對應的英文單詞就是enhancement,中文翻譯為增強,加強,提高,充實的意思。所以epoll模型會顯
Linux網路程式設計——I/O複用之poll函式
#include <string.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/select.h> #include <sys/time.
網路程式設計-I/O複用
## I/O模型 Unix下可用的I/O模型有五種: + 阻塞式I/O + 非阻塞式I/O + I/O複用(select和poll、epoll) + 訊號驅動式I/O(SIGIO) + 非同步I/O(POSIX的aio_系列函式) > 詳見Unix網路程式設計卷一第六章 sel
Linux網路程式設計---I/O多路複用之select
1.I/O多路複用(IO multiplexing) 我們之前講了I/O多路複用和其他I/O的區別,在這裡,我們再具體討論下I/O多路複用是怎麼工作? I/O 多路複用技術就是為了解決程序或執行緒阻塞到某個 I/O 系統呼叫而出現的技術,使程序不阻塞於某個特定的 I/O 系統呼叫。
Linux網路程式設計---I/O多路複用之epoll
/* TCP伺服器 用法:./server port */ #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <errno.h> #include <string
Linux 高效能伺服器程式設計—— I/O複用 epoll
一 核心事件表 epoll不同於select和poll,它是使用一組函式來完成任務;同時,epoll把使用者關心的檔案描述符上的事件放在核心裡的一個事件表中,從而不像select 和 poll每次呼叫都需要重複傳入檔案描述符集或事件集。但是epoll需要一個額外的檔案描述符來表示核
Linux 高效能伺服器程式設計——I/O複用 poll
一:poll系統呼叫 同select相似,也是在指定時間內輪詢一定數量的檔案描述符,以測試其中是否有就緒者。 二:poll函式 1.函式原型: #include<poll.h> int poll(struct pollfd* fds,nfds
Linux高效能伺服器程式設計——I/O複用 select
提出背景 不管是多執行緒,或者多程序,以及執行緒池,程序池。他們都存在一定的效率問題。 1.每個程序或執行緒只能為一個客戶端進行服務,知道該客戶端結束。(如果客戶端在同一時間的訪問數量特別大呢?) 2.當客戶端傳送來資料後,分配執行緒或程序為其服務完後,就要等
Linux----網路程式設計(IO複用之epoll系統呼叫函式)
伺服器端epoll.c #include <stdio.h> #include <string.h> #include <stdlib.h> #include <assert.h> #include <unistd.h&
18.Linux下的I/O複用與epoll詳解
為什麼引出epoll? 1.select的缺點 1.select所用到的FD_SET是有限的 /linux/posix_types.h: #define __FD_SETSIZE 102
Linux----網路程式設計(IO複用中select,poll,epoll之間的區別)
前面學習了select、poll和epoll三組IO複用系統呼叫,現在從向核心傳遞檔案描述符數、核心實現、檢索就緒描述符方式、工作模式和時間複雜度等五個方面比較其中的區別,以明確在實際應用中應該選擇使用哪個。 由於select與poll的特性相似,所以把它們聯絡在一起與ep
I/O複用模型之select函式用法——伺服器開發
現在我們介紹另外一種常用併發伺服器開發的技術——select函式I/O複用模型。 先來介紹select及相關的函式: select函式的作用是監聽指定的多個I/O的檔案描述符,在設定的時間內阻塞,當有一個或者多個I/O埠滿足某個“讀”或者“寫”的條件,則在fd_set型別
高階I/O複用技術:Epoll的使用及一個完整的C例項
高效能的網路伺服器需要同時併發處理大量的客戶
Linux----網路程式設計(I/O複用之select系統呼叫)
io_select_ser.c 1. #include <string.h> 2. #include <assert.h> 3. #include <unistd.h> 4. #include <stdio.h> 5. #in
Linux網路程式設計——tcp併發伺服器(I/O複用之select)
與多執行緒、多程序相比,I/O複用最大的優勢是系統開銷小,系統不需要建立新的程序或者執行緒,也不必維護這些執行緒和程序。 程式碼示例: #include <stdio.h> #include <unistd.h> #include <
Linux網路程式設計之I/O複用迴圈伺服器
原文:http://blog.csdn.net/chenjin_zhong/article/details/7270166 1.介紹 在前幾節,我們介紹了迴圈伺服器,併發伺服器. 簡單的迴圈伺服器每次只能處理一個請求,即處理的請求是序列的。而併發伺服器可以通過建立多
Linux I/O複用之select函式詳解
置頂 2017年02月12日 20:50:08 難免有錯_ 閱讀數:7438更多 select函式的功能和呼叫順序 使用select函式時統一監視多個檔案描述符的: 1、 是否存在套接字接收資料? 2、 無需阻塞傳輸資料的套接字有哪些? 3、 哪些套接字發生了
網路程式設計中I/O複用select的用法
網路程式設計select的用法 select使用流程圖 在網路程式設計中需要新增的程式碼行以及意義 例程 參考文獻及部落格 注:本文對select函式、相關引數及結構體不做解釋 select使用流程
網路程式設計 筆記(八) I/O複用
select函式呼叫示例 #include <stdio.h> #include <unistd.h> #include <sys/time.h> #include <sys/select.h> #defi