实验10 事件I/O

简介:

spacer.gif实验10 事件I/O

事件I/O

select 函数的局限性

a)进程所能同时打开的文件描述符个数受FD_SETSIZE 大小的限制

b)每当select 函数返回可用的文件描述符集合后,应用都不得不对所有已

注册的文件描述符进行遍历比对,以确定哪个描述符上发生了事件,从而对其进

行读写操作

要掌握的函数

Epoll 通过三个系统调用完成了高效的I/O 模型的实现

epoll_create,初始化epoll 上下文环境

epoll_ctl,向epoll 上下文中添加或去除需要系统监视的文件描述符

epoll_wait,等待文件描述符上发生事件

2.1 epoll_create 函数

int epoll_create (int size)

返回值:文件描述符表示成功,-1 表示错误,errno 记录错误号

例如:

int epfd;

epfd = epoll_create (100);

if (epfd < 0)

perror ("epoll_create");

2.2 epoll_ctl 函数

/* epoll 环境中添加,删除,改变要监视的文件描述符*/

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

返回值:表示成功,-1 表示错误,errno 记录错误号

调用参数:

epfdepoll_create  创建的epoll 环境句柄

op,规定对fd 的操作方式

event,事件

2.3 函数epoll_wait

#include <sys/epoll.h>

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

返回值:发生事件的文件描述符个数表示成功,-1 表示错误,errno 记录错误号

程序的具体过程:

3.1 注册文件描述符到epoll

struct epoll_event event;

int ret;

/* 将来epoll 会返回此fd 给应用*/

event.data.fd = fd;

/* 监视此fd 上的可读和可写事件*/




spacer.gifevent.events = EPOLLIN | EPOLLOUT;

ret = epoll_ctl (epfd, EPOLL_CTL_ADD, fd, &event);

if (ret)

perror ("epoll_ctl");

3.2 修改epoll 监视事件

struct epoll_event event;

int ret;

/* 将来epoll 会返回此fd 给应用*/

event.data.fd = fd;

/* 监视此fd 上的可读事件*/

event.events = EPOLLIN;

ret = epoll_ctl (epfd, EPOLL_CTL_MOD, fd, &event);

if (ret) perror ("epoll_ctl");

3.3 取消epoll 监视的文件描述符

struct epoll_event event;

int ret;

ret = epoll_ctl (epfd, EPOLL_CTL_DEL, fd, &event);

if (ret) perror ("epoll_ctl");

3.4 等待epoll 事件发生,随后变量events 事件

int nr_events = epoll_wait (epfd, events, MAX_EVENTS, -1);

/* epoll 返回的nr_events 个事件依次遍历,进行处理*/

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

printf ("event=%ld on fd=%d\n",  events[i].events,events[i].data.fd);

/*

处理events[i].data.fd 文件描述符.

*/

}

程序示例

#include <sys/socket.h>

#include <sys/epoll.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <fcntl.h>

#include <unistd.h>

#include <stdio.h>

#include <errno.h>

#define BUFSIZE 512

#define OPEN_MAX 100



spacer.gif#define PORT 5001

#define MAX_EVENTS 20

char buf[BUFSIZE];

struct epoll_event events[MAX_EVENTS];

void setnonblocking(int sock)

{

int flag;

fcntl(sock,F_GETFL,&flag);

fcntl(sock,F_SETFL,flag|O_NONBLOCK);

};

int main()

{

int listenfd=socket(AF_INET,SOCK_STREAM,0);

setnonblocking(listenfd);

struct sockaddr_in cli,svr;

inet_aton("0.0.0.0",&svr.sin_addr);

svr.sin_port=htons(PORT);

svr.sin_family=AF_INET;

//产生epoll 实例的文件描述符

int efd=epoll_create(256);

//设置epoll 事件,将fd 加入ev.data.fd  是为了返回的时候知道是哪个套接字

可读或者可写

struct epoll_event ev;

ev.data.fd=listenfd;

ev.events=EPOLLIN|EPOLLET;

//注册epoll 事件,将在listenfd(第个参数上)检测,如果有事件,会返回

ev,注意ev 已经拷贝到了内核,可以重新使用ev 注册其他事件

epoll_ctl(efd,EPOLL_CTL_ADD,listenfd,&ev);

int br=bind(listenfd,(struct sockaddr*)&svr,sizeof svr);

if(br<0){printf("error bind!\r\n");exit(-1);};

listen(listenfd,20);

while(1)

{

int nev=epoll_wait(efd,events,MAX_EVENTS,-1);

if(nev<0){printf("error  epoll_wait!\r\n");exit(-1);};

int i=0;

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



spacer.gif{

if(listenfd==events[i].data.fd)

{

//监听套接字可读

int len=sizeof  cli;

int confd=accept(listenfd,(struct  sockaddr*)&cli,&len);

if(confd<=0){printf("error!\r\n");exit(-1);};

printf("servergotaconnection

%s:%d\r\n",inet_ntoa(cli.sin_addr),htons(cli.sin_port));

setnonblocking(confd);

ev.data.fd=confd;

ev.events==EPOLLIN|EPOLLET;

epoll_ctl(efd,EPOLL_CTL_ADD,confd,&ev);

continue;

}

if(events[i].events&EPOLLIN)

{

int n=read(events[i].data.fd,buf,BUFSIZE);

if((n<0)&&(errno!=ECONNRESET))

{

printf("error in read!\r\n");

exit(-1);

}

if(n<=0)

{

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

epoll_ctl(efd,EPOLL_CTL_DEL,events[i].data.fd,&events[i]);

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

}

else

{

buf[n]=0;

printf("%s\r\n",buf);

}

}//end of if E_POLLIN

}//end of for

}//end of while

}

from

边沿触发ET 和水平触发LT

水平触发模式下,以读模式为例,只要被监视的套接字接收缓存中有可读数据,



spacer.gifepoll_wait  立刻返回。边沿触发,只有当套接字缓存收到了数据时,epoll_wait

才会返回,即使缓存中还有上次没有读完的数据。





本文转自陈仲阳0 51CTO博客,原文链接:http://blog.51cto.com/wolfword/1240346

相关文章
|
3天前
LabVIEW使用多个事件结构来处理同一个事件
LabVIEW使用多个事件结构来处理同一个事件
|
2月前
|
XML 算法 C语言
【C/C++ 静态代码检查工具 Cppcheck 】Cppcheck 检测器列表和检查规则大全一览
【C/C++ 静态代码检查工具 Cppcheck 】Cppcheck 检测器列表和检查规则大全一览
96 0
|
9月前
|
JavaScript API
StencilJs 学习之事件
其实并没有所谓的 stencil Event,相反 stencil 鼓励使用 DOM event。然而,Stencil 提供了一个 API 来指定组件可以触发的事件,以及组件监听的事件。 这是通过 Event()和 Listen()装饰器实现的。
53 0
|
10月前
|
API 数据安全/隐私保护 容器
上机实验7 组件及事件处理
上机实验7 组件及事件处理
119 0
onInterceptTouchEvent() 与 onTouch() 事件分析
onInterceptTouchEvent() 与 onTouch() 事件分析
onInterceptTouchEvent() 与 onTouch() 事件分析
|
算法
m基于wcdma的软切换性能matlab仿真,对比平均激活集数(MASN)激活集更新率(ASUR)以及呼叫中断概率(OP)三个性能指标
m基于wcdma的软切换性能matlab仿真,对比平均激活集数(MASN)激活集更新率(ASUR)以及呼叫中断概率(OP)三个性能指标
85 0
m基于wcdma的软切换性能matlab仿真,对比平均激活集数(MASN)激活集更新率(ASUR)以及呼叫中断概率(OP)三个性能指标
|
机器学习/深度学习 算法 知识图谱
视频事件检测(下)| 学习笔记
快速学习视频事件检测(下),介绍了视频事件检测(下)系统机制, 以及在实际应用过程中如何使用。
180 0
视频事件检测(下)| 学习笔记
|
机器学习/深度学习 人工智能 监控
视频事件检测(上)| 学习笔记
快速学习视频事件检测(上),介绍了视频事件检测(上)系统机制, 以及在实际应用过程中如何使用。
361 0
视频事件检测(上)| 学习笔记