epoll的使用

關於epollhtml

    上一篇博文提到過select的使用方法。今天說一下epoll的使用方法。epoll相對於select而言有以下幾個方面的優勢:python

  • 對於要監聽的fd的數量沒有限制linux

  • 內核會保存須要監聽的fd,無需每次都進行初始化數組

  • 只返回產生事件(可讀取、可寫等)的fd,無需遍歷監聽的全部fdsocket

     使用epoll主要用進行一步阻塞的調用。其基本的步驟爲函數

  • 首先經過epoll_create調用建立一個epoll文件描述符(epfd)ui

  • 經過epoll_ctl對這個描述符進行設置,具體包括:添加須要監聽的文件描述符、socket描述符等;設置相關監聽的類型(例如監聽是否可讀:EPOLLIN,)等spa

  • 經過epoll_wait進行事件的監聽htm

       看一段代碼示例:事件

       #include <sys/epoll.h>

#include <unistd.h>

#include <stdlib.h>

#include <sys/types.h>

 

int main(int argc, char* argv[])

{

  //epoll_event用於epoll_ctl中與關聯的fd進行設置,events用於epoll_wait返回能夠處理的fd的信息

   struct epoll_event epollEvent, events[10];

   //監聽時間設置爲可讀時觸發

   epollEvent.events = EPOLLIN ;

   epollEvent.data.fd = 0;

   char buf[100];

  //建立epfd

   int epollFd = epoll_create(10);

   const char* errStr = "epoll_Create failed\n";

  //若是建立失敗,則返回

   if(epollFd < 0)

   {

       

       write(2, errStr, 20);

       exit(-1);

   }

   errStr = "epoll_ctl failed\n";

 //監聽標準輸入, 將stdin添加至監聽fd集合中

   if(-1 == epoll_ctl(epollFd, EPOLL_CTL_ADD, 0, &epollEvent))

   {

       write(2, errStr, 17);

       exit(-1);

   }

   int nfds;

   const char* splitLine = "----------\n";

   while(1)

   {

     //當stdin可讀時,epoll_wait返回,超時時間設置爲一直阻塞,知道有可用的fd時返回

       nfds = epoll_wait(epollFd, events, 10, -1);

       int i;

      //對可用的fd進行處理

       for(i = 0; i < nfds; ++i)

       {

           int readCount = read(events[i].data.fd, buf, 5);

           if(0 == readCount)

           {

               close(epollFd);

               exit(0);

           }

           write(1, buf, readCount);

           write(1, splitLine, 11);

       }

       //epoll_ctl(epollFd, EPOLL_CTL_MOD, 0, &epollEvent);

   }

   close(epollFd);

   return 0;

}

輔助的python腳本

#!/usr/bin/env python

#coding:utf-8


import time


output_str = "hello world"


for i in range(0, 5):

   print output_str

   time.sleep(2)

gcc -o test_epoll test_epoll.c -g -Wall

python cat_py.py | ./test_epoll

下面具體講解一下每一個函數的用法,詳情請參考linux的官方文檔(http://man7.org/linux/man-pages/man7/epoll.7.html),

     頭文件#include <sys/epoll.h>

     函數原型:int epoll_create(int size);

size爲須要監聽的文件描述的數量,內核用該值去分分配相應的空間,可是自從內核2.6.8以後,使用動態的空間分配方式,size的取值已經被忽略,可是必須設置爲大於0的數值。該函數的返回值爲epoll的文件描述符,該描述符將用於後續的epoll_ctl和epoll_wait等的操做。

函數原型: int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

其中epfd爲epoll_create的返回值,就是epoll的文件描述符,全部須要監聽的fd都須要與epfd進行關聯。

op爲EPOLL_CTL_ADD、EPOLL_CTL_MOD和EPOLL_CTL_DEL三者之一EPOLL_CTL_ADD用於添加須要監聽的文件描述符,即參數中的fd,將fd添加到須要監聽的文件描述符集合中。EPOLL_CTL_MOD用於改變與fd進行關聯的event。EPOLL_CTL_DEL用於將fd從監聽的集合中刪除。

對於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 */

};

此處主要設置epoll_event中的events,events的取值主要由EPOLLIN、EPOLLOUT、EPOLLRDHUP和EPOLLET等具體參考http://man7.org/linux/man-pages/man2/epoll_ctl.2.html  

EPOLLIN監聽fd是否可讀,EPOLLOUT監聽fd是否可寫。須要着重指出的是:epoll默認的事件觸發機制是水平觸發,所以若是使用EPOLLET則設置爲邊緣觸發,對於邊緣觸發,在一次觸發之後(epoll_wait返回處理後)要須要再次調用epoll_ctl使用EPOLL_CTL_MOD進行事件關聯。不然若是本次處理不徹底,例若有2k的字節可讀,而只讀取了1k,若是再也不次設置,則再次調用epoll_wait後不會返回,於是可能會形成數據的丟失。epoll_data與fd想關聯,保存着fd相關的信息。

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

epfd爲epoll的fd,events爲返回的對應fd的event的數組,maxevents爲一次能夠處理的fd的最大數量,一般設置爲須要監聽的fd的數量,timeout爲超時返回的秒數。若是爲0,則當即返回,若是爲-1則一直阻塞,直到有須要處理的fd則返回。epoll_wait的返回值爲目前可用的fd的數量。另外,若是發生錯誤則返回-1並設置errno。

相關文章
相關標籤/搜索