epool使用詳解

來源:互聯網
上載者:User

原文地址:http://www.cnblogs.com/haippy/archive/2012/01/09/2317269.html


------------------------

epoll簡介

epoll 是Linux核心中的一種可擴充IO事件處理機制,最早在 Linux 2.5.44核心中引入,可被用於代替POSIX select 和 poll 系統調用,並且在具有大量應用程式請求時能夠獲得較好的效能( 此時被監視的檔案描述符數目非常大,與舊的 select 和 poll 系統調用完成操作所需 O(n) 不同, epoll能在O(1)時間內完成操作,epool用了特殊的結構體epoll_data,裡麵包含了IO請求的詳細資料,當IO活躍時,根據epool_data裡存的資訊,在O(1)的時間內就可以定位的IO事件,不必掃描整個fd集合,所以效能相當高),epoll 與 FreeBSD的kqueue類似,都向使用者空間提供了自己的檔案描述符來進行操作。

int epoll_create(int size);

建立一個epoll的控制代碼,size用來告訴核心需要監聽的數目一共有多大。當建立好epoll控制代碼後,它就是會佔用一個fd值,在linux下如果查看/proc/進程id/fd/,是能夠看到這個fd的,所以在使用完epoll後,必須調用close() 關閉,否則可能導致fd被耗盡。

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

epoll的事件註冊函數,第一個參數是 epoll_create() 的傳回值,第二個參數表示動作,使用如下三個宏來表示:

EPOLL_CTL_ADD    //註冊新的fd到epfd中;EPOLL_CTL_MOD    //修改已經註冊的fd的監聽事件;EPOLL_CTL_DEL    //從epfd中刪除一個fd;

第三個參數是需要監聽的fd,第四個參數是告訴核心需要監聽什麼事,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)來說的。EPOLLONESHOT//只監聽一次事件,當監聽完這次事件之後,如果還需要繼續監聽這個socket的話,需要再次把這個socket加入到EPOLL隊列裡。

當對方關閉串連(FIN), EPOLLERR,都可以認為是一種EPOLLIN事件,在read的時候分別有0,-1兩個傳回值。

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

參數events用來從核心得到事件的集合,maxevents 告之核心這個events有多大,這個 maxevents 的值不能大於建立 epoll_create() 時的size,參數 timeout 是逾時時間(毫秒,0會立即返回,-1將不確定,也有說法說是永久阻塞)。該函數返回需要處理的事件數目,如返回0表示已逾時。

EPOLL事件有兩種模型 Level Triggered (LT) 和 Edge Triggered (ET):

LT(level triggered,水平觸發模式)是預設的工作方式,並且同時支援 block 和 non-block socket。在這種做法中,核心告訴你一個檔案描述符是否就緒了,然後你可以對這個就緒的fd進行IO操作。如果你不作任何操作,核心還是會繼續通知你的,所以,這種模式編程出錯誤可能性要小一點。

ET(edge-triggered,邊緣觸發模式)是高速工作方式,只支援no-block socket。在這種模式下,當描述符從未就緒變為就緒時,核心通過epoll告訴你。然後它會假設你知道檔案描述符已經就緒,並且不會再為那個檔案描述符發送更多的就緒通知,等到下次有新的資料進來的時候才會再次出發就緒事件。 epoll 例子

我們將實現一個簡單的TCP 伺服器,該迷你伺服器將會在標準輸出上列印處用戶端發送的資料,首先我們建立並綁定一個 TCP 通訊端:

static intcreate_and_bind (char *port){  struct addrinfo hints;  struct addrinfo *result, *rp;  int s, sfd;  memset (&hints, 0, sizeof (struct addrinfo));  hints.ai_family = AF_UNSPEC;     /* Return IPv4 and IPv6 choices */  hints.ai_socktype = SOCK_STREAM; /* We want a TCP socket */  hints.ai_flags = AI_PASSIVE;     /* All interfaces */  s = getaddrinfo (NULL, port, &hints, &result);  if (s != 0)    {      fprintf (stderr, "getaddrinfo: %s\n", gai_strerror (s));      return -1;    }  for (rp = result; rp != NULL; rp = rp->ai_next)    {      sfd = socket (rp->ai_family, rp->ai_socktype, rp->ai_protocol);      if (sfd == -1)        continue;      s = bind (sfd, rp->ai_addr, rp->ai_addrlen);      if (s == 0)        {          /* We managed to bind successfully! */          break;        }      close (sfd);    }  if (rp == NULL)    {      fprintf (stderr, "Could not bind\n");      return -1;    }  freeaddrinfo (result);  return sfd;}


create_and_bind() 包含了如何建立 IPv4 和 IPv6 通訊端的代碼塊,它接受一字串作為連接埠參數,並在 result 中返回一個 addrinfo 結構,

struct addrinfo{  int              ai_flags;  int              ai_family;  int              ai_socktype;  int              ai_protocol;  size_t           ai_addrlen;  struct sockaddr *ai_addr;  char            *ai_canonname;  struct addrinfo *ai_next;};

如果函數成功則返回通訊端,如果失敗,則返回 -1,

 

下面,我們將一個通訊端設定為非阻塞形式,函數如下:

static intmake_socket_non_blocking (int sfd){  int flags, s;  flags = fcntl (sfd, F_GETFL, 0);  if (flags == -1)    {      perror ("fcntl");      return -1;    }  flags |= O_NONBLOCK;  s = fcntl (sfd, F_SETFL, flags);  if (s == -1)    {      perror ("fcntl");      return -1;    }  return 0;}

接下來,便是主函數代碼,主要用於事件迴圈:

#define MAXEVENTS 64intmain (int argc, char *argv[]){  int sfd, s;  int efd;  struct epoll_event event;  struct epoll_event *events;  if (argc != 2)    {      fprintf (stderr, "Usage: %s [port]\n", argv[0]);      exit (EXIT_FAILURE);    }  sfd = create_and_bind (argv[1]);  if (sfd == -1)    abort ();  s = make_socket_non_blocking (sfd);  if (s == -1)    abort ();  s = listen (sfd, SOMAXCONN);  if (s == -1)    {      perror ("listen");      abort ();    }  efd = epoll_create1 (0);  if (efd == -1)    {      perror ("epoll_create");      abort ();    }  event.data.fd = sfd;  event.events = EPOLLIN | EPOLLET;  s = epoll_ctl (efd, EPOLL_CTL_ADD, sfd, &

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.