日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

学习使用epoll

發布時間:2024/1/17 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 学习使用epoll 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

epoll是Linux下多路復用IO接口select/poll的增強版本,它能顯著減少程序在大量并發連接中只有少量活躍的情況下的系統CPU利用率。

?

?

一、epoll的優點

支持一個進程打開大數目的socket描述符

IO效率不隨FD數目增加而線性下降

?

二、epoll的使用

epoll有2種工作方式:LTET。?  

LT(level?triggered,水平觸發是缺省的工作方式,并且同時支持blockno-block?socket.在這種做法中,

內核告訴你一個文件描述符是否就緒了,然后你可以對這個就緒的fd進行IO操作。如果你不作任操作,

內核還是會繼續通知你的,所以,這種模式編程出錯誤可能性要小一點。傳統的select/poll都是這種模型

的代表。?  

?

ET?(edge-triggered,邊緣觸發是高速工作方式,只支持no-block?socket。在這種模式下,當描述符從未

就緒變為就緒時,內核通過epoll告訴你。然后它會假設你知道文件描述符已經就緒,并且不會再為那個文

件描述符發送更多的就緒通知,直到你做了某些操作導致那個文件描述符不再為就緒狀態了(比如,你在

發送,接收或者接收請求,或者發送接收的數據少于一定量時導致了一個EWOULDBLOCK?錯誤)。但是

請注意,如果一直不對這個fdIO操作(從而導致它再次變成未就緒),內核不會發送更多的通知

only?once

?

epoll相關的系統調用有3個epoll_create,?epoll_ctlepoll_wait。在頭文件<sys/epoll.h>

?

1.?int?epoll_create(int?size);

創建一個epoll句柄,即圖中的epfd, 用來監聽事件,?size用來告訴內核這個監聽的數目一共有多大。

這個參數不同于select()中的第一個參數,給出最大監聽的fd+1的值。需要注意的是,當創建好epoll句柄后,它就是會占用一個fd值,所以在使用完epoll后,必須調用close()關閉,否則可能導致fd被耗盡

?

2.?int?epoll_ctl(int?epfd,?int?op,?int?fd,?struct?epoll_event?*event);

參數op是操作類型, 使用這個方法完成3種操作: 

EPOLL_CTL_ADD:注冊新的fdepfd中;
EPOLL_CTL_MOD:修改已經注冊的fd的監聽事件;
EPOLL_CTL_DEL:從epfd中刪除一個fd

(1) 注冊新事件

C代碼 ?
  • struct?epoll_event?ev; ??
  • ev.data.fd?=?fd; ??
  • ev.events?=?EPOLLIN; ??
  • epoll_cntl(epfd,?EPOOL_CTL_ADD,?fd,?&ev);??
  • struct epoll_event ev; ev.data.fd = fd; ev.events = EPOLLIN; epoll_cntl(epfd, EPOOL_CTL_ADD, fd, &ev);?

    ?

    ?

    (2) 修改監聽事件

    ?

    C代碼 ?
  • struct?epoll_event?*a_event?=?get_a_event()? ??
  • struct?epoll_event?ev; ??
  • ev.data.fd?=?a_event->data.fd; ??
  • ev.events?=?a_event->events?|?EPOLLOUT; ??
  • epoll_cntl(epfd,?EPOOL_CTL_MOD,?a_event->data.fd,?&ev);??
  • struct epoll_event *a_event = get_a_event() struct epoll_event ev; ev.data.fd = a_event->data.fd; ev.events = a_event->events | EPOLLOUT; epoll_cntl(epfd, EPOOL_CTL_MOD, a_event->data.fd, &ev);?

    ?

    (3) 刪除事件

    ?

    C代碼 ?
  • struct?epoll_event?*a_event?=?get_a_event()? ??
  • struct?epoll_event?ev; ??
  • ev.data.fd?=?a_event->data.fd; ??
  • epoll_cntl(epfd,?EPOOL_CTL_DEL,?a_event->data.fd,?&ev);??
  • struct epoll_event *a_event = get_a_event() struct epoll_event ev; ev.data.fd = a_event->data.fd; epoll_cntl(epfd, EPOOL_CTL_DEL, a_event->data.fd, &ev);?

    ?

    3種操作都使用了一個ev變量, 這個變量用來關聯fd和它的監聽事件, 是臨時的,?可以反復使用.

    ev是一個struct epoll_event結構體, 結構如下:

    ?

  • 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?*/??
  • };??
  • ?

    events可以是以下幾個宏的集合:
    EPOLLIN?:表示對應的文件描述符可以讀(包括對端SOCKET正常關閉);
    EPOLLOUT:表示對應的文件描述符可以寫;
    EPOLLPRI:表示對應的文件描述符有緊急的數據可讀(這里應該表示有帶外數據到來);
    EPOLLERR:表示對應的文件描述符發生錯誤;
    EPOLLHUP:表示對應的文件描述符被掛斷;
    EPOLLET:?將EPOLL設為邊緣觸發(Edge?Triggered)模式,這是相對于水平觸發(Level?Triggered)來說的。

    注意多個socket可以設置不同的觸發模式
    EPOLLONESHOT:只監聽一次事件,當監聽完這次事件之后,如果還需要繼續監聽這個socket的話,需要再次把這個socket加入到EPOLL隊列里


    3.?int?epoll_wait(int?epfd,?struct?epoll_event?*?events,?int?maxevents,?int?timeout);

    等待事件的產生, 把產生的事件存放到events數組里, 如圖中所示, 調用epoll_wait后,?

    fd 1和 fd 3和fd k產生了事件, 把它們分別存放到events[0], events[1], events[2]
    參數epfdepoll_create()函數返回的epoll句柄。

    參數eventsstruct?epoll_event結構指針,用來從內核得到事件的集合

    參數?maxevents內核這個events有多大

    參數?timeout:?等待時的超時時間,以毫秒為單位。

    返回值:成功時,返回需要處理的事件數目。調用失敗時,返回0,表示等待超時。

    ?

    ?

    三 epoll實例 -- 模擬HTTP服務器?

    ?

    ?

    C代碼 ?
  • #include?<sys/socket.h> ??
  • #include?<sys/wait.h> ??
  • #include?<netinet/in.h> ??
  • #include?<netinet/tcp.h> ??
  • #include?<sys/epoll.h> ??
  • #include?<sys/sendfile.h> ??
  • #include?<sys/stat.h> ??
  • #include?<unistd.h> ??
  • #include?<stdio.h> ??
  • #include?<stdlib.h> ??
  • #include?<string.h> ??
  • #include?<strings.h> ??
  • #include?<fcntl.h> ??
  • #include?<errno.h>? ??
  • ??
  • #define?MAX_EVENTS?10 ??
  • #define?PORT?8080 ??
  • ??
  • //設置socket連接為非阻塞模式 ??
  • void?setnonblocking(int?sockfd)?{ ??
  • ????int?opts; ??
  • ??
  • ????opts?=?fcntl(sockfd,?F_GETFL); ??
  • ????if(opts?<?0)?{ ??
  • ????????perror("fcntl(F_GETFL)\n"); ??
  • ????????exit(1); ??
  • ????} ??
  • ????opts?=?(opts?|?O_NONBLOCK); ??
  • ????if(fcntl(sockfd,?F_SETFL,?opts)?<?0)?{ ??
  • ????????perror("fcntl(F_SETFL)\n"); ??
  • ????????exit(1); ??
  • ????} ??
  • } ??
  • ??
  • int?main(){ ??
  • ????struct?epoll_event?ev,?events[MAX_EVENTS]; ??
  • ????int?addrlen,?listenfd,?conn_sock,?nfds,?epfd,?fd,?i,?nread,?n; ??
  • ????struct?sockaddr_in?local,?remote; ??
  • ????char?buf[BUFSIZ]; ??
  • ??
  • ????//創建listen?socket ??
  • ????if(?(listenfd?=?socket(AF_INET,?SOCK_STREAM,?0))?<?0)?{ ??
  • ????????perror("sockfd\n"); ??
  • ????????exit(1); ??
  • ????} ??
  • ????bzero(&local,?sizeof(local)); ??
  • ????local.sin_family?=?AF_INET; ??
  • ????local.sin_addr.s_addr?=?htonl(INADDR_ANY);; ??
  • ????local.sin_port?=?htons(PORT); ??
  • ????if(?bind(listenfd,?(struct?sockaddr?*)?&local,?sizeof(local))?<?0)?{ ??
  • ????????perror("bind\n"); ??
  • ????????exit(1); ??
  • ????} ??
  • ????listen(listenfd,?20); ??
  • ??
  • ????epfd?=?epoll_create(MAX_EVENTS); ??
  • ????if?(epfd?==?-1)?{ ??
  • ????????perror("epoll_create"); ??
  • ????????exit(EXIT_FAILURE); ??
  • ????} ??
  • ??
  • ????ev.events?=?EPOLLIN; ??
  • ????ev.data.fd?=?listenfd; ??
  • ????if?(epoll_ctl(epfd,?EPOLL_CTL_ADD,?listenfd,?&ev)?==?-1)?{ ??
  • ????????perror("epoll_ctl:?listen_sock"); ??
  • ????????exit(EXIT_FAILURE); ??
  • ????} ??
  • ??
  • ????for?(;;)?{ ??
  • ????????nfds?=?epoll_wait(epfd,?events,?MAX_EVENTS,?-1); ??
  • ????????if?(nfds?==?-1)?{ ??
  • ????????????perror("epoll_pwait"); ??
  • ????????????exit(EXIT_FAILURE); ??
  • ????????} ??
  • ??
  • ????????for?(i?=?0;?i?<?nfds;?++i)?{ ??
  • ????????????fd?=?events[i].data.fd; ??
  • ????????????if?(fd?==?listenfd)?{ ??
  • ????????????????conn_sock?=?accept(listenfd, ??
  • ????????????????????????(struct?sockaddr?*)?&remote,?&addrlen); ??
  • ????????????????if?(conn_sock?==?-1)?{ ??
  • ????????????????????perror("accept"); ??
  • ????????????????????exit(EXIT_FAILURE); ??
  • ????????????????} ??
  • ????????????????setnonblocking(conn_sock); ??
  • ????????????????ev.events?=?EPOLLIN?|?EPOLLET; ??
  • ????????????????ev.data.fd?=?conn_sock; ??
  • ????????????????if?(epoll_ctl(epfd,?EPOLL_CTL_ADD,?conn_sock, ??
  • ????????????????????????????&ev)?==?-1)?{ ??
  • ????????????????????perror("epoll_ctl:?add"); ??
  • ????????????????????exit(EXIT_FAILURE); ??
  • ????????????????} ??
  • ????????????????continue; ??
  • ????????????}?? ??
  • ????????????if?(events[i].events?&?EPOLLIN)?{ ??
  • ????????????????n?=?0; ??
  • ????????????????while?((nread?=?read(fd,?buf?+?n,?BUFSIZ-1))?>?0)?{ ??
  • ????????????????????n?+=?nread; ??
  • ????????????????} ??
  • ????????????????buf[n]?=?'\0'; ??
  • ??
  • ????????????????ev.data.fd?=?fd; ??
  • ????????????????ev.events?=?events[i].events?|?EPOLLOUT; ??
  • ????????????????if?(epoll_ctl(epfd,?EPOLL_CTL_MOD,?fd,?&ev)?==?-1)?{ ??
  • ????????????????????perror("epoll_ctl:?mod"); ??
  • ????????????????} ??
  • ????????????} ??
  • ????????????if?(events[i].events?&?EPOLLOUT)?{ ??
  • ????????????????sprintf(buf,?"HTTP/1.1?200?OK\r\nContent-Length:?%d\r\n\r\nHello?World",?11); ??
  • ????????????????n?=?strlen(buf); ??
  • ????????????????if?(write(fd,?buf,?n)?<?n)?{ ??
  • ????????????????????perror("write"); ??
  • ????????????????} ??
  • ????????????????close(fd); ??
  • ????????????} ??
  • ????????} ??
  • ????} ??
  • ??
  • ????return?0; ??
  • }??
  • #include <sys/socket.h> #include <sys/wait.h> #include <netinet/in.h> #include <netinet/tcp.h> #include <sys/epoll.h> #include <sys/sendfile.h> #include <sys/stat.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <strings.h> #include <fcntl.h> #include <errno.h> #define MAX_EVENTS 10 #define PORT 8080 //設置socket連接為非阻塞模式 void setnonblocking(int sockfd) { int opts; opts = fcntl(sockfd, F_GETFL); if(opts < 0) { perror("fcntl(F_GETFL)\n"); exit(1); } opts = (opts | O_NONBLOCK); if(fcntl(sockfd, F_SETFL, opts) < 0) { perror("fcntl(F_SETFL)\n"); exit(1); } } int main(){ struct epoll_event ev, events[MAX_EVENTS]; int addrlen, listenfd, conn_sock, nfds, epfd, fd, i, nread, n; struct sockaddr_in local, remote; char buf[BUFSIZ]; //創建listen socket if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("sockfd\n"); exit(1); } bzero(&local, sizeof(local)); local.sin_family = AF_INET; local.sin_addr.s_addr = htonl(INADDR_ANY);; local.sin_port = htons(PORT); if( bind(listenfd, (struct sockaddr *) &local, sizeof(local)) < 0) { perror("bind\n"); exit(1); } listen(listenfd, 20); epfd = epoll_create(MAX_EVENTS); if (epfd == -1) { perror("epoll_create"); exit(EXIT_FAILURE); } ev.events = EPOLLIN; ev.data.fd = listenfd; if (epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev) == -1) { perror("epoll_ctl: listen_sock"); exit(EXIT_FAILURE); } for (;;) { nfds = epoll_wait(epfd, events, MAX_EVENTS, -1); if (nfds == -1) { perror("epoll_pwait"); exit(EXIT_FAILURE); } for (i = 0; i < nfds; ++i) { fd = events[i].data.fd; if (fd == listenfd) { conn_sock = accept(listenfd, (struct sockaddr *) &remote, &addrlen); if (conn_sock == -1) { perror("accept"); exit(EXIT_FAILURE); } setnonblocking(conn_sock); ev.events = EPOLLIN | EPOLLET; ev.data.fd = conn_sock; if (epoll_ctl(epfd, EPOLL_CTL_ADD, conn_sock, &ev) == -1) { perror("epoll_ctl: add"); exit(EXIT_FAILURE); } continue; } if (events[i].events & EPOLLIN) { n = 0; while ((nread = read(fd, buf + n, BUFSIZ-1)) > 0) { n += nread; } buf[n] = '\0'; ev.data.fd = fd; ev.events = events[i].events | EPOLLOUT; if (epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &ev) == -1) { perror("epoll_ctl: mod"); } } if (events[i].events & EPOLLOUT) { sprintf(buf, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\n\r\nHello World", 11); n = strlen(buf); if (write(fd, buf, n) < n) { perror("write"); } close(fd); } } } return 0; }?

    轉載于:https://www.cnblogs.com/armlinux/archive/2011/11/26/2396774.html

    總結

    以上是生活随笔為你收集整理的学习使用epoll的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。