epoll是linux 2.6加入的用于I/O事件多路分离的一组函数,这组函数简化了反应式socket服务器的编程,并且很大程度提高了性能。从一定程度上弥补了LINUX内核对异步I/O支持的不足,epoll机制加上非阻塞I/0可以模拟实现异步I/O。本文主要是说明如何使用epoll机制来编写一个echo服务器。
epoll用到的所有函数都是在头文件sys/epoll.h中声明的,下面简要说明所用到的数据结构和函数:
所用到的数据结构
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 被用于注册所感兴趣的事件和回传所发生待处理的事件,其中epoll_data 联合体用来保存触发事件的某个文件描述符相关的数据,例如一个client连接到服务器,服务器通过调用accept函数可以得到于这个client对应 的socket文件描述符,可以把这文件描述符赋给epoll_data的fd字段以便后面的读写操作在这个文件描述符上进行。epoll_event 结构体的events字段是表示感兴趣的事件和被触发的事件可能的取值为:
EPOLLIN :表示对应的文件描述符可以读;
EPOLLOUT:表示对应的文件描述符可以写;
EPOLLPRI:表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来);
EPOLLERR:表示对应的文件描述符发生错误;
EPOLLHUP:表示对应的文件描述符被挂断;
EPOLLET:表示对应的文件描述符有事件发生;
所用到的函数:
1、epoll_create函数
函数声明:
int epoll_create(int size
)
该函数生成一个epoll专用的文件描述符,其中的参数是指定生成描述符的最大范围(我觉得这个参数和select函数的第一个参数应该是类似的但是该怎么设置才好,我也不太清楚)。
2、epoll_ctl函数
函数声明:
int epoll_ctl(int epfd
, int op
, int fd
, struct epoll_event *event
)
该函数用于控制某个文件描述符上的事件,可以注册事件,修改事件,删除事件。
参数:epfd:由
epoll_create 生成的epoll专用的文件描述符;
op:要进行的操作例如注册事件,可能的取值
EPOLL_CTL_ADD 注册、
EPOLL_CTL_MOD 修
改、
EPOLL_CTL_DEL 删除
fd:关联的文件描述符;
event:指向epoll_event的指针;
如果调用成功返回0,不成功返回-1
3、epoll_wait函数
函数声明:
int epoll_wait(int epfd,
struct epoll_event * events,
int maxevents,
int timeout)
该函数用于轮询I/O事件的发生;
参数:
epfd:由
epoll_create 生成的epoll专用的文件描述符;
epoll_event:用于回传代处理事件的数组;
maxevents:每次能处理的事件数;
timeout:等待I/O事件发生的超时值;
返回发生事件数。
例子:
<iostream><sys socket.h=""><sys epoll.h=""><netinet in.h=""><arpa inet.h=""><fcntl.h><unistd.h>#include </unistd.h></fcntl.h></arpa></netinet></sys></sys></iostream><<iostream><sys socket.h=""><sys epoll.h=""><netinet in.h=""><arpa inet.h=""><fcntl.h><unistd.h>iostream</unistd.h></fcntl.h></arpa></netinet></sys></sys></iostream>>
<iostream><sys socket.h=""><sys epoll.h=""><netinet in.h=""><arpa inet.h=""><fcntl.h><unistd.h><iostream>
#include </iostream></unistd.h></fcntl.h></arpa></netinet></sys></sys><<iostream><sys socket.h=""><sys epoll.h=""><netinet in.h=""><arpa inet.h=""><fcntl.h><unistd.h>sys/socket.h</unistd.h></fcntl.h></arpa></netinet></sys></sys></iostream>>
<iostream><sys socket.h=""><sys epoll.h=""><netinet in.h=""><arpa inet.h=""><fcntl.h><unistd.h>
#include </unistd.h></fcntl.h></arpa></netinet></sys></sys></iostream><<iostream><sys socket.h=""><sys epoll.h=""><netinet in.h=""><arpa inet.h=""><fcntl.h><unistd.h>sys/epoll.h</unistd.h></fcntl.h></arpa></netinet></sys></sys></iostream>>
<iostream><sys socket.h=""><sys epoll.h=""><netinet in.h=""><arpa inet.h=""><fcntl.h><unistd.h>
#include </unistd.h></fcntl.h></arpa></netinet></sys></sys></iostream><<iostream><sys socket.h=""><sys epoll.h=""><netinet in.h=""><arpa inet.h=""><fcntl.h><unistd.h>netinet/in.h</unistd.h></fcntl.h></arpa></netinet></sys></sys></iostream>>
<iostream><sys socket.h=""><sys epoll.h=""><netinet in.h=""><arpa inet.h=""><fcntl.h><unistd.h>
#include </unistd.h></fcntl.h></arpa></netinet></sys></sys></iostream><<iostream><sys socket.h=""><sys epoll.h=""><netinet in.h=""><arpa inet.h=""><fcntl.h><unistd.h>arpa/inet.h</unistd.h></fcntl.h></arpa></netinet></sys></sys></iostream>>
<iostream><sys socket.h=""><sys epoll.h=""><netinet in.h=""><arpa inet.h=""><fcntl.h><unistd.h>
#include </unistd.h></fcntl.h></arpa></netinet></sys></sys></iostream><<iostream><sys socket.h=""><sys epoll.h=""><netinet in.h=""><arpa inet.h=""><fcntl.h><unistd.h>fcntl.h</unistd.h></fcntl.h></arpa></netinet></sys></sys></iostream>>
<iostream><sys socket.h=""><sys epoll.h=""><netinet in.h=""><arpa inet.h=""><fcntl.h><unistd.h>
#include </unistd.h></fcntl.h></arpa></netinet></sys></sys></iostream><<iostream><sys socket.h=""><sys epoll.h=""><netinet in.h=""><arpa inet.h=""><fcntl.h><unistd.h>unistd.h</unistd.h></fcntl.h></arpa></netinet></sys></sys></iostream>>
<iostream><sys socket.h=""><sys epoll.h=""><netinet in.h=""><arpa inet.h=""><fcntl.h><unistd.h>
#include </unistd.h></fcntl.h></arpa></netinet></sys></sys></iostream><<iostream><sys socket.h=""><sys epoll.h=""><netinet in.h=""><arpa inet.h=""><fcntl.h><unistd.h>stdio.h</unistd.h></fcntl.h></arpa></netinet></sys></sys></iostream>>
<iostream><sys socket.h=""><sys epoll.h=""><netinet in.h=""><arpa inet.h=""><fcntl.h><unistd.h><stdio.h>
#define MAXLINE 10
#define OPEN_MAX 100
#define LISTENQ 20
#define SERV_PORT 5555
#define INFTIM 1000
void setnonblocking(int sock)
{
int opts;
opts=fcntl(sock,F_GETFL);
if(opts<0)
{
perror("fcntl(sock,GETFL)");
exit(1);
}
opts = opts|O_NONBLOCK;
if(fcntl(sock,F_SETFL,opts)<0)
{
perror("fcntl(sock,SETFL,opts)");
exit(1);
}
}
int main()
{
int i, maxi, listenfd, connfd, sockfd,epfd,nfds;
ssize_t n;
char line[MAXLINE];
socklen_t clilen;
//声明epoll_event结构体的变量,ev用于注册事件,数组用于回传要处理的事件
struct epoll_event ev,events[20];
//生成用于处理accept的epoll专用的文件描述符
epfd=epoll_create(256);
struct sockaddr_in clientaddr;
struct sockaddr_in serveraddr;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
//把socket设置为非阻塞方式
setnonblocking(listenfd);
//设置与要处理的事件相关的文件描述符
ev.data.fd=listenfd;
//设置要处理的事件类型
ev.events=EPOLLIN|EPOLLET;
//注册epoll事件
epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&ev);
bzero(&serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
char *local_addr="200.200.200.204";
inet_aton(local_addr,&(serveraddr.sin_addr));//htons(SERV_PORT);
serveraddr.sin_port=htons(SERV_PORT);
bind(listenfd,(sockaddr *)&serveraddr, sizeof(serveraddr));
listen(listenfd, LISTENQ);
maxi = 0;
for ( ; ; ) {
//等待epoll事件的发生
nfds=epoll_wait(epfd,events,20,500);
//处理所发生的所有事件
for(i=0;i<nfds;++i)
{
if(events[i].data.fd==listenfd)
{
connfd = accept(listenfd,(sockaddr *)&clientaddr, &clilen);
if(connfd<0){
perror("connfd<0");
exit(1);
}
setnonblocking(connfd);
char *str = inet_ntoa(clientaddr.sin_addr);
std::cout<<"connect from "<_u115 ?tr<<std::endl;
//设置用于读操作的文件描述符
ev.data.fd=connfd;
//设置用于注测的读操作事件
ev.events=EPOLLIN|EPOLLET;
//注册ev
epoll_ctl(epfd,EPOLL_CTL_ADD,connfd,&ev);
}
else if(events[i].events&EPOLLIN)
{
if ( (sockfd = events[i].data.fd) < 0) continue;
if ( (n = read(sockfd, line, MAXLINE)) < 0) {
if (errno == ECONNRESET) {
close(sockfd);
events[i].data.fd = -1;
} else
std::cout<<"readline error"<<std::endl;
} else if (n == 0) {
close(sockfd);
events[i].data.fd = -1;
}
//设置用于写操作的文件描述符
ev.data.fd=sockfd;
//设置用于注测的写操作事件
ev.events=EPOLLOUT|EPOLLET;
//修改sockfd上要处理的事件为EPOLLOUT
epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);
}
else if(events[i].events&EPOLLOUT)
{
sockfd = events[i].data.fd;
write(sockfd, line, n);
//设置用于读操作的文件描述符
ev.data.fd=sockfd;
//设置用于注测的读操作事件
ev.events=EPOLLIN|EPOLLET;
//修改sockfd上要处理的事件为EPOLIN
epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);
}
}
}
}</stdio.h></unistd.h></fcntl.h></arpa></netinet></sys></sys></iostream></iostream>
分享到:
相关推荐
epoll用到的所有函数都是在头文件sys/epoll.h中声明的,本文简要说明所用到的数据结构和函数。
linux socket tcp epoll使用教程 例子 源代码
Linux下通过epoll机制进行串口监听,当收到数据时,通过tcp进行数据转发给服务器
linux系统下,利用epoll接收串口助手发来的数据并打印。
linux下epoll示例程序 服务器端 客服端 实现多人聊天
linux下的epoll服务程序及客户端实例,服务程序支持多连接,并能稳定进行数据传输。
Linux下基于epoll_线程池高并发服务器实现研究,研究Linux的人可以看看。
epoll在内核版本2.6以上才出现的新的函数,而他们在linux内核中的实现都是十分相似。 这三种函数都需要设备驱动提供poll回调函数,对于套接字而言,他们是 tcp_poll,udp_poll和datagram_poll; 对于自己开发的设备...
Windows完成端口介绍 Linux EPOLL介绍 同步I/O与异步I/O 说起完成端口,它的实现机制其实是重叠I/O实现异步I/O操作,下面就结合同步I/O来解释下什么是异步I/O
但是一直到2.6内核发布,网络模块的AIO一直没有进入稳定内核版本(大部分都是使用用户线程模拟方法,在使用了NPTL的linux上面其实和windows的完成端口基本上差不多了)。2.6内核所支持的AIO特指磁盘的AIO---支持io_...
linux 网络编程 epoll 简单示例 客户端 源码 只为学习epoll用 有不妥之处欢迎指正
linux下epoll网络模型介绍 简单讲解如何使用epoll模型, linux下epoll网络模型介绍 简单讲解如何使用epoll模型
一个Linux下对epoll封装的类,方便初学者
大并发服务器编程模型 windows iocp完成端口模型可支持1万大并发,但是linux能作到5万大并发
linux epoll 例子程序
linux 通过 epoll 实现 tcp 服务器 代码
linux中 epoll poll 和select的区别
该源代码使用linux的网络IO多路复用模型epoll在建立tcpserver,对用队列来缓存请求,使用线程池来处理请求。
本程序以简单的例子介绍了Linux中epoll的用法
linux 网络编程 epoll 简单示例 服务端 只为学习用 有不妥之处欢迎指正