epoll相關(guān)

epoll 相關(guān)

標簽(空格分隔): linux c/c++


1.epoll_create調(diào)用

int epoll_create(int size);
int epoll_create1(int flags);
  • 第一個函數(shù)epoll_create調(diào)用是比較常用的調(diào)用,第二個調(diào)用是改進版本。內(nèi)核版本在2.9以及之后才能夠使用。
  • 調(diào)用成功的返回值,是一個文件描述符(非負整數(shù)),指向一個epoll實例,這個文件描述符代表這后續(xù)對于epoll相關(guān)接口的引用。需要在使用結(jié)束后調(diào)用close關(guān)閉文件描述符。
  • 調(diào)用出現(xiàn)錯誤的返回值是-1,并可以在全局變量error中查看錯誤信息。
  • 第一個調(diào)用的參數(shù)size是,調(diào)用者在后續(xù)使用epoll添加感興趣的文件描述符個數(shù)的大小,這個是一個給系統(tǒng)初次分配epoll監(jiān)控文件描述符數(shù)據(jù)結(jié)構(gòu)的內(nèi)存空間的一個參考值,但是如果后來調(diào)用者,監(jiān)聽的事件超過這個范圍,那么系統(tǒng)會額外的分配空間的。
    總的來說這個值只是操作系統(tǒng)的參考值。
  • epoll_create1參數(shù)是一個文件描述符標志,如果為0那么和 epoll_create(0)一樣。

2 epoll_ctl調(diào)用

2.1函數(shù)原型

#include <sys/epoll.h>
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

2.2參數(shù)說明

2.2.1 event參數(shù)

結(jié)構(gòu)體定義

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 */
};
  • epoll_event中events變量為事件發(fā)生的類型,可以是下面提到的事件類型EPOLLIN,EPOLLOUT,EPOLLHDUP,EPOLLPRI,EPOLLERR,EPOLLHUP,EPOLLET,EPOLLONESHOT,EPOLLWAKEUP中的一種,具體的參見下面的事件類型說明。
  • data為一個聯(lián)合體,可以根據(jù)不同的事件,來表示用戶數(shù)據(jù)內(nèi)容。例如可以是一個文件描述符。

2.2.2 fd參數(shù)

fd為需要監(jiān)控的文件描述符。在這里是根據(jù)這個文件描述符對后面的event結(jié)構(gòu)進行操作的。具體見下面的op參數(shù).

2.2.3 op參數(shù)

  • EPOLL_CTL_ADD:將文件描述符fd關(guān)聯(lián)到event結(jié)構(gòu)當中,并把event事件添加到epfd實例當中。相當于把fd注冊到epoll實例當中。
  • EPOLL_CTL_MOD:根據(jù)文件描述符fd,來找到fd在epoll實例當中對應的event結(jié)構(gòu),修改這個event結(jié)構(gòu)。
  • EPOLL_CTL_DEL:根據(jù)文件描述符fd,找到其所對應的文件event結(jié)構(gòu),刪除這個fd上面的事件監(jiān)控。
  • 總結(jié)下,epoll實際是通過fd來構(gòu)建一個event事件,通過這個event結(jié)構(gòu)來監(jiān)控fd上面發(fā)生的文件事件操作。

2.2.4 epdf參數(shù)

epfd為epoll_create 或者epoll_create1函數(shù)調(diào)用的返回值,實際為一個文件描述符,指向epoll實例。epoll系統(tǒng)操作都是通過這個文件描述符來進行的。

2.3返回值

  • 調(diào)用成功返回0
  • 失敗返回-1,并置error錯誤信息。

3 epoll_wait調(diào)用

3.1函數(shù)原型

#include <sys/epoll.h>
int epoll_wait(int epfd, struct epoll_event *events,
                int maxevents, int timeout);
int epoll_pwait(int epfd, struct epoll_event *events,
                int maxevents, int timeout,const sigset_t *sigmask);

3.2參數(shù)說明

3.2.1 timeout參數(shù)

  • timeout參數(shù)指定了在沒有事件發(fā)生的時候epoll_wait調(diào)用阻塞的毫秒數(shù)(milliseconds)。
  • 如果把這個值設置為-1,那么在沒有事件發(fā)生時,這個調(diào)用會永遠的阻塞下去。
  • 如果timeout=0那么epoll_wait會檢查監(jiān)控的事件是否發(fā)生,然后立刻返回。
  • 上面指的事件,可以包含監(jiān)控的文件事件,也可以是信號中斷事件。

3.2.2 maxevent參數(shù)

  • maxevent,是一次調(diào)用epoll_wait可以返回有監(jiān)控事件發(fā)生的最大個數(shù)。
  • 例如監(jiān)控的事件中在某一時刻可能有20個發(fā)生了,但是如果這個時候maxevent=10,那么只會返回10個發(fā)生的事件。

3.2.3 events參數(shù)

  • events表示的是一個struct epoll_event數(shù)組,存放的是某個時刻發(fā)生事件的結(jié)構(gòu)體
  • 可以在epoll_wait調(diào)用結(jié)束之后,來訪問這個結(jié)構(gòu)體里面的內(nèi)容例如fd來處理發(fā)生的文件事件。

3.2.4 epfd參數(shù)

  • epfd為epoll_create函數(shù)返回的文件描述符。epoll實例。

3.3返回值

  • 沒有任何事件發(fā)生,或者超時返回0。
  • 出現(xiàn)錯誤返回-1,并設置error錯誤信息。
  • 返回監(jiān)控事件發(fā)生的個數(shù)。

4.使用方法

下面是一個處理多個客戶端連接的服務端程序,可以根據(jù)這個大體的框架和自己的情況進行修改。

#include<stdio.h>
#include<unistd.h>
#include<sys/epoll.h>
#define MAX_EVENTS 10
int main (int argc,char* argv[] ) {
    struct epoll_event ev, events[MAX_EVENTS];
    int listen_sock, conn_sock, nfds, epollfd;

    /* Code to set up listening socket, 'listen_sock',
       (socket(), bind(), listen()) omitted */
    /*創(chuàng)建epoll實例*/
    epollfd = epoll_create1(0);
    if (epollfd == -1) {
        perror("epoll_create1");
        exit(EXIT_FAILURE);
    }

    /*設置epoll_event,關(guān)聯(lián)到epoll實例*/
    ev.events = EPOLLIN;
    ev.data.fd = listen_sock;
    /*注冊listen_sock到epoll實例*/
    if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listen_sock, &ev) == -1) {
        perror("epoll_ctl: listen_sock");
        exit(EXIT_FAILURE);
    }
    for (;;) {
        /*監(jiān)控事件的發(fā)生,-1表示檢查監(jiān)控的事件后立即返回*/
        nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);
        if (nfds == -1) {
            perror("epoll_wait");
            exit(EXIT_FAILURE);
        }
        
        /*遍歷返回的事件,對事件進行處理*/
        for (n = 0; n < nfds; ++n) {
            /*如果是發(fā)生在接收連接的套接字上,那么接受客戶端連接,并監(jiān)控新建的連接文件事件*/
            if (events[n].data.fd == listen_sock) {
                conn_sock = accept(listen_sock,
                        (struct sockaddr *) &local, &addrlen);
                if (conn_sock == -1) {
                    perror("accept");
                    exit(EXIT_FAILURE);
                }
                setnonblocking(conn_sock);
                /*設置新連接文件事件為讀寫事件*/
                ev.events = EPOLLIN | EPOLLET;
                ev.data.fd = conn_sock;
                /*添加到epoll實例中,進行監(jiān)控*/
                if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock,
                            &ev) == -1) {
                    perror("epoll_ctl: conn_sock");
                    exit(EXIT_FAILURE);
                }
            }/*如果發(fā)生的事件不是在接收連接的套接字上面*/ 
            else {
                /*處理產(chǎn)生的新的連接的數(shù)據(jù),例如,讀取客戶端寫的數(shù)據(jù),或者向客戶端寫數(shù)據(jù)*/
                do_use_fd(events[n].data.fd);
            }
        }
    }
}

4.參考內(nèi)容

  • Linux man epoll_create
  • Linux man epoll_ctl
  • Linux man epoll_wait
  • Unix 網(wǎng)絡編程 卷I 套接字聯(lián)網(wǎng)API
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容