1. 程式人生 > >I/O多路轉接-epoll

I/O多路轉接-epoll

原本 oid com pue tdi 數據 錯誤 系統 val

By francis_hao Aug 5,2017

APUE講多路轉接的章節介紹了select、pselect和poll函數。而epoll是linux內核在2.5.44引入的。在glibc 2.3.2添加了支持。

epoll_create – 打開一個epoll文件描述符

epoll_ctl – 控制epoll文件描述符接口

epoll_wait – 在epoll文件描述符上等待一個I/O事件

概述

#include <sys/epoll.h>
int epoll_create(int size);
int epoll_ctl(int epfd, int op,

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

描述

epoll_create()

創建一個epoll(7)實例,返回指向這個實例的文件描述符,這個文件描述符會被之後的epoll函數使用,當該文件描述符不再需要的時候,應當使用close(2)關閉。當所有指向同一個epoll實例的文件描述符都被關閉後,內核會銷毀該實例,釋放分配的資源以復用。

參數size原本用來告訴內核要添加到epoll實例中文件描述符的數量,內核用這個參數作為一個大概的分配空間大小的指示,以存放描述事件的結構體數據。但是從內核2.6.8之後,這個參數就不再需要了,內核會動態的分配需要的空間大小。但是參數size必須依然是大於0的數,以確保新的epoll函數運行在舊的內核上時能向後兼容。

函數執行成功返回非負的文件描述符,若有錯誤則返回-1,而且errno被置為相應的值以指示該錯誤。

epoll_ctl()

這個系統調用對由文件描述符epfd指定的epoll實例執行控制操作,同時需要指定目標文件描述符fd,和對其的操作op。有效的op參數如下

op

說明

EPOLL_CTL_ADD

註冊目標文件描述符fd到epoll實例,並關聯事件event

EPOLL_CTL_MOD

改變關聯到目標文件描述符fd的事件event

EPOLL_CTL_DEL

從epoll實例移除目標文件描述符,event被忽略,可以是NULL

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可以是以下常量的按位或集:

events

說明

EPOLLIN

關聯的文件可以進行read(2)操作

EPOLLOUT

關聯的文件可以進行write(2)操作

EPOLLRDHUP

(since Linux 2.6.17)

對方關閉了流套接字連接,or shut down writing half of connection。

EPOLLPRI

有緊急數據可以進行read(2)操作

EPOLLERR

在關聯的文件描述上發生了錯誤,epoll_wait(2)總會等待這一事件,因此無需對此位置位

EPOLLHUP

關聯的文件描述符掛起(Hang up)了,poll_wait(2)總會等待這一事件,因此無需對此位置位

EPOLLET

為關聯的文件描述符設置邊沿觸發,默認的行為是電平觸發(Level Triggered)

EPOLLONESHOT

(since Linux 2.6.2)

為關聯的文件描述符設置單次行為,這意味著該文件描述符一旦由epoll_wait(2)返回一次事件,就會被內部失能,再不會有其他事件被報告,用戶程序必須調用epoll_ctl()函數,使用EPOLL_CTL_MOD命令重新關聯event

函數執行成功返回0,錯誤返回-1,而且errno被置為相應的值。

epoll_wait()

該系統調用等待由文件描述符epfd指定的epoll實例上的事件,由events指向的內存區域包含了準備好的事件。至多有maxevents個事件由epoll_wait()返回,該值必須大於0。timeout參數指定epoll_wait()將最多阻塞多長時間(ms)。指定-1使epoll_wait() to block indefinitely,而指定0使epoll_wait()立即返回,即使沒有事件準備好。

函數執行成功返回準備好的文件描述符的數量,如果在timeout時間內仍然沒有文件描述符準備好則返回0,錯誤返回-1,而且errno被置為相應的值。

實例

一個簡單的用法:

#include <sys/epoll.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
int epoll_fd;
int fds_num;
char str[50]={0};
struct epoll_event ev_in,ev_out;
fds_num = 0;

epoll_fd = epoll_create(2); /*this ‘size‘ argument is ignored*/
if (-1 == epoll_fd){
perror("epoll_create");
return -1;
}
memset(&ev_in, 0, sizeof (ev_in));
memset(&ev_out, 0, sizeof (ev_out));
ev_in.events = EPOLLIN;
if (-1 == epoll_ctl(epoll_fd, EPOLL_CTL_ADD, 0, &ev_in)){/*Register the target file descriptor 0,that is stdin*/
perror("epoll_ctl");
return -1;
}

#define TIMEOUT 20
while(1){
fds_num = epoll_wait(epoll_fd, &ev_out, 5, TIMEOUT*1000);
//fds_num = epoll_wait(epoll_fd, &ev_out, 5, -1);
if (-1 == fds_num){
perror("epoll_wait");
return -1;
}else if (0 == fds_num){
printf("none data within %u s\n",TIMEOUT);
return 0;
}
if ( 0 == ev_out.data.fd){
if ((ev_out.events & EPOLLIN) != 0){
//printf("events is %x\n",ev_out.events);
if (-1 == read(0, str, 50)){
perror("read");
return -1;
}
printf("%s",str);
memset(str, 0 ,sizeof (str));
}
}else{
printf("%d\n",ev_out.data.fd);
}
}
return 0;
}

執行結果:

技術分享

技術分享
本文由 劉英皓 創作,采用 知識共享 署名-非商業性使用-相同方式共享 3.0 中國大陸 許可協議進行許可。歡迎轉載,請註明出處:
轉載自:http://www.cnblogs.com/yinghao1991/

參考

I/O多路轉接-epoll