epoll嵌入式linux,Linux中IO多路复用接口epoll的使用

Linux中IO多路复用接口epoll的使用

在C语言的IO模型中,大家可能接触和学习过selelct、 poll等实现IO多路复用的函数接口,这些接口在windows下或者linux下都是支持的,但是分析select和poll就会发现他们在使用的过程中存在一些问题,比如 select函数可以检测的文件描述符的个数有限制,多支持1024个,而poll呢在检测大量的描述符的时候占用CPU的时间会显著的增加,针对他们存在的这些问题呢,我们下边来学习epoll函数接口来弥补他们的不足。

epoll接口是linux中特有的,其他平台是不支持的。epoll接口可以检测的描述符的个数要远大于select,而且使用的灵活性更高。接下来我们来分析一下epoll的函数API,它主要包括三个函数:epoll_create、epoll_ctl、epoll_wait。

nt epoll_create(int size);

功能:创建一个epoll的标示符。

参数:size 现在已经无用,并不表示检测的大值。

返回值:就是获得的epoll的标示符。

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

功能:控制需要检测的文件描述符。

参数:epfd: epoll_create得到的标识符。

op:表示此次调用要执行的操作,包括添加描述符、删除和修改属性。

EPOLL_CTL_ADD 添加描述符

EPOLL_CTL_DEL 删除描述符

EPOLL_CTL_MOD 修改描述符触发的属性

fd: 要检测的文件描述符的值

event: 执行要检测的描述符的特性,结构体成员如下

struct epoll_event

{

uint32_t events; /* Epoll events ,指定描述符被检测的条件*/

epoll_data_t data; /* User data variable */

};

typedef union epoll_data

{

void *ptr;

int fd;

uint32_t u32;

uint64_t u64;

} epoll_data_t;

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

功能:等待就绪的文件描述符

参数:epfd: epoll_create得到的标识符

events: 用来存储就绪的文件描述符状态的结构体数组指针

maxevents: 指定要检测的描述符的大个数

timeout: 指定超时检测的时间(如果不指定超时,将该参数指定为-1即可)

返回值:就绪的文件描述符的个数。

下边是一个使用epoll接口实现的基于tcp协议的服务器代码:

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define N 1000

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

{

int listenfd, connectfd;

struct sockaddr_in serveradd, clientadd;

unsigned int size = sizeof(clientadd);

int ret, i = 0;

ssize_t bytes;

int epfd ;

/*

*even用来添加新的描述符

*even_list用来接收回传的准备好的描述符

*/

struct epoll_event even, even_list[N];

char buf[128] = {0};

bzero(even_list, sizeof(struct epoll_event) * N);

/*

*将所有的结构体中的描述符都初始化为-1.

*/

for (i = 0; i < N; i++) {

even_list[i].data.fd = -1;

}

bzero(&serveradd, sizeof(serveradd));

bzero(&clientadd, sizeof(clientadd));

serveradd.sin_family = AF_INET;

serveradd.sin_port = htons(9999);

serveradd.sin_addr.s_addr = htonl(INADDR_ANY);

signal(SIGCHLD, SIG_IGN);

if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {

perror("fail to create socket");

return -1;

}

if (bind(listenfd, (struct sockaddr*)&serveradd, sizeof(serveradd)) < 0) {

perror("fail to bind the server!");

close(listenfd);

return -1;

}

if (listen(listenfd, 20) < 0) {

perror("fail to listen");

close(listenfd);

return -1;

}

if ((epfd = epoll_create(1)) < 0) {

perror("fail to epoll_create");

close(listenfd);

return -1;

}

even.events = EPOLLIN;

even.data.fd = listenfd;

if (epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &even) < 0) {

perror("fail to epoll_ctl");

close(listenfd);

close(epfd);

return -1;

}

while (1) {

/*返回准备好的描述符的个数,

*准备好的描述符被存放在even_list中

*/

ret = epoll_wait(epfd, even_list, N, -1);

if (ret < 0) {

perror("fail to epoll_wait");

continue;

}

printf("ret = %d\n", ret);

//遍历准备好的描述符

for (i = 0; i < ret; i++) {

if (even_list[i].events == EPOLLIN) {

if (even_list[i].data.fd == listenfd) {

connectfd = accept(listenfd, (struct sockaddr*)&clientadd, &size);

printf("client add: %s, port :%d\n", inet_ntoa(clientadd.sin_addr),

ntohs(clientadd.sin_port));

even.events = EPOLLIN;

even.data.fd = connectfd;

epoll_ctl(epfd, EPOLL_CTL_ADD, connectfd, &even);

} else {

bytes = recv(even_list[i].data.fd, buf, sizeof(buf), 0);

if (bytes == 0) {

close(even_list[i].data.fd);

epoll_ctl(epfd, EPOLL_CTL_DEL, even_list[i].data.fd, &even_list[i]);

//将不再被监听的描述符移除之后,重新将该下标的描述符赋值为-1

even_list[i].data.fd = -1;

even_list[i].events = 0;

}

sprintf(buf, "%d bytes has recv!\n", bytes);

send(even_list[i].data.fd, buf, sizeof(buf), 0);

}

}

}

}

close(listenfd);

return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值