基於select
的i/o
復用技術速度慢的原因:
呼叫select
函式後常見的針對所有檔案描述符的迴圈語句。
每次呼叫select
函式後都需要向該函式傳遞監視物件資訊。
epoll
函式的優點正好與select
缺點相反:
無需編寫以監視狀態變化為目的的針對所有檔案描述符的迴圈語句。
呼叫對應於select
函式的epoll-wait
函式時無需每次傳遞監視物件資訊。
實現epoll
時必要的函式:
epoll_create:
建立儲存epoll
檔案描述符的空間。
epoll_ctl
:向空間註冊或銷毀檔案描述符。
epoll_wait
:與select
函式類似,等待檔案描述符發生變化。
宣告足夠大的epoll_event
結構體陣列後,傳遞給epoll_wait
函式時,發生變化的檔案描述符資訊將被填入該陣列。
因此,無需像select
函式那樣針對所有檔案描述符進行迴圈。
基於epoll
的回聲伺服器端:
#include #include #include #include #include #include #include #define buf_size 100
#define epoll_size 50
void error_handling(char *buf);
int main(int argc, const char * argv)
serv_sock = socket(pf_inet, sock_stream, 0);
if(serv_sock == -1)
error_handling("socket() error");
memset(&serv_adr, 0, sizeof(serv_adr));
serv_adr.sin_family = af_inet;
serv_adr.sin_addr.s_addr = htonl(inaddr_any);
serv_adr.sin_port = htons(atoi(argv[1]));
if(bind(serv_sock, (struct sockaddr *) &serv_adr, sizeof(serv_adr)) == -1)
error_handling("bind() error");
if(listen(serv_sock, 5) == -1)
error_handling("listen() error");
//建立檔案描述符的儲存空間稱為「epoll例程」
epfd = epoll_create(epoll_size);
ep_events = malloc(sizeof(struct epoll_event) *epoll_size);
//新增讀取事件的監視(註冊事件)
event.events = epollin; //讀取資料事件
event.data.fd = serv_sock;
epoll_ctl(epfd, epoll_ctl_add, serv_sock, &event);
while (1)
//服務端套接字和客服端套接字
for (i = 0; i < event_cnt; i++)
else //連線之後傳遞資料
else}}
}close(serv_sock);
close(epfd);
return 0;
}void error_handling(char *message)
條件觸發和邊緣觸發
條件觸法方式中,
只要輸入緩衝中還剩有資料,
就將以事件方式再次註冊.epoll
預設使用該方式.
邊緣觸發中輸入緩衝收到資料時僅註冊一次事件,
即使輸入緩衝中還留有資料,
也不會再進行註冊.
實現邊緣觸發的回聲伺服器端
1.邊緣觸發方式中,
接收資料時僅註冊一次該事件,
因此,一旦發生輸入相關事件,
就應該讀取輸入緩衝中的全部資料.
因此需要驗證輸入緩衝是否為空.
read
函式返回-1,
變數error
中的值為eagain
時,說明沒有資料可讀.
2..邊緣觸發方式下,
以阻塞方式工作的read
和write
函式有可能引起伺服器端的長時間停頓,
所以需要將套接字變成非阻塞模式.
#include#include#include#include#include#include#include#include#include#define buf_size 4 //驗證邊緣觸發的工作方式,將緩衝設定為4位元組
#define epoll_size 50
void error_handling(char *message);
void setnonblockingmode(int fd);
int main(int argc, char *argv)
serv_sock = socket(pf_inet,sock_stream,0);
memset(&serv_adr,0,sizeof(serv_adr));
serv_adr.sin_family = af_inet;
serv_adr.sin_addr.s_addr = htonl(inaddr_any);
serv_adr.sin_port = htons(atoi(argv[1]));
if (bind(serv_sock, (struct sockaddr*) &serv_adr, sizeof(serv_adr)) == -1)
error_handling("bind() error!");
if (listen(serv_sock,5) == -1)
error_handling("listen() error!");
epfd = epoll_create(epoll_size); //建立epoll例程檔案描述符
ep_events = malloc(sizeof(struct epoll_event) * epoll_size);
setnonblockingmode(serv_sock);
event.events = epollin;
event.data.fd = serv_sock;
epoll_ctl(epfd, epoll_ctl_add, serv_sock, &event); //在epfd內註冊監視serv__sock,監視其讀取資料的情況
while(1)
puts("return epoll_wait");
for (i = 0; i < event_cnt; i++)
else //連線客戶端套接字讀取資料
else if(str_len < 0)
else
} }
} }
close(serv_sock);
close(epfd);
return 0;
} void setnonblockingmode(int fd)
void error_handling(char *message)
從實現模型的角度看,
邊緣觸發更有可能帶來高效能,
但不能簡單地認為」只要使用邊緣觸發就一定能提高速度」.
unique ptr優於auto ptr的原因
使用auto ptr不當的後果 int main aptr1將控制權移交給aptr2,然而編譯階段並不認為輸出 aptr1是錯誤的,然而編譯階段錯誤總比執行階段錯誤要好 int main unique ptr的指標不允許上述賦值,因為uptr1之後的操作可能會導致執行階段失敗 unique ptr只...
C 的函式物件優於函式指標地方
自 在c 程式語言中,有很多功能都與c語言相通,比如指標的應用等等。在這裡我們介紹的則是一種類似於函式指標的c 函式物件的相關介紹。c 函式物件不是函式指標。但是,在程式 中,它的呼叫方式與函式指標一樣,後面加個括號就可以了。這是入門級的隨筆,說的是函式物件的定義,使用,以及與函式指標,成員函式指標...
select的列子說明select內部實現原理
1 select內部是個陣列,而epoll內部結構是紅黑二叉樹 2 select查詢起來慢,而epoll查詢起來快 3 每次迴圈,內部都要發生拷貝 檢視相關 而epoll不需要這樣的操作,也就是初始化一次拷貝 include include include include include int m...