将检测文件描述符的变化委托给内核去处理,然后内核将发生变化的文件描述符对应的事件返回给应用程序。
更多技术文档参见:https://github.com/IsConor/C_and_C_plus.git
函数介绍
Int epoll_create( int size );
函数说明:创建一个树根
参数说明:
Size:最大节点数,此参数在Linux2.6.8已被忽略,但必须传递一个大于0的数
返回值:
成功:返回一个大于0的文件描述符,代表整个树的树根。
失败:返回-1,并设置errno值。
函数介绍
Int epoll_ctl( int epfd, ?int op, ?int fd, ?struct epoll_event * event );
函数说明:将要监听的节点在epoll树上添加,删除和修改
参数说明:
epfd: epoll树根
op:
EPOLL_CTL_ADD: 添加事件节点到树上
EPOLL_CTL_DEL: 从树上删除事件节点
EPOLL_CTL_MOD: 修改树上对应的事件节点
fd:事件节点对应的文件描述符
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_data_t data;
};
event.events常用的有:
EPOLLIN: 读事件
EPOLLOUT:写事件
EPOLLERR:错误事件
EPOLLET:边缘触发模式
Event.data.fd: 要监控的事件对应的文件描述符
函数介绍
Int epoll_wait( int epfd, ?struct epoll_event * events, ?int maxevents, ?int timeout );
函数说明:委托内核监控epoll树的事件节点
函数参数:
Epfd: epoll树根
Events: 传出参数,结构体数组
Maxevents:events数组大小
Timeout:
-1:一直阻塞
0:表示不阻塞
>0:表示超时的时长
1 设置socket,得到文件描述符lfd
2 设置端口复用 --- setsockopt()
3 绑定 --- bind()
4 监听 ---- listen()
5 创建一颗epoll树
Int epfd = epoll_create();
//将监听描述符上树
struct epoll_event ev;
ev.events = EPOLLIN;
ev.data.fd = lfd;
epoll_ctl( epfd, ?EPOLL_CTL_ADD, ?lfd, ?&ev );
Struct epoll_event events[1024];
While(1)
{
Nready = epoll_wait( epfd, ?events, ?1024, ?-1 );
If( nready < 0 )
{
If( errno == EINTR )
{
Continue;
}
Break;
}
For( i=0; i<nready; i++ )
{
Sockfd = events[i].data.fd;
//有客户端连接请求到来
If( sockfd == lfd )
{
cfd = accept( lfd, NULL, NULL );
//将cfd对应的读事件上epoll树
ev.data.fd = cfd;
ev.events = EPOLLIN;
epoll_ctl( epfd, ?EPOLL_CTL_ADD, ?cfd, ?&ev );
continue;
}
//有客户端发送数据过来
N = read( sockfd, ?buf, ?sizeof(buf) );
If(n <= 0)
{
Close(sockfd);
//将sockfd对应的事件节点从epoll树上删除
Epoll_ctl( epfd, ?EPOLL_CTL_DEL, ?sockfd, ?NULL );
Printf(“read error or client close\n”);
Continue;
}
Else
{
Write( sockfd, ?buf, ?n );
}
}
}
Close ( lfd );
Return 0;
epoll的两种工作模式
epoll有两种工作模式 ET 和 LT 模式
水平触发:高电平代表1
只要缓冲区中有数据,就一直通知
边缘触发:电平有变化就代表1
缓冲区中有数据只会通知一次,之后再有数据才会通知
1 Epoll默认情况下是LT模式,在这种模式下,若读数据一次性没有读完,缓冲区内还有可读数据,则epoll_wait还会再次通知
2 若将epoll设置为ET模式,若读数据的时候一次性没有读完,则epoll_wait不再通知,直到下次有新的数据发来
Epoll的ET模式的非阻塞模式:
在ET模式下,如何在epoll_wait返回一次的情况下读完数据?
循环读数据,直到读完数据,但是读完数据后会阻塞
若能一次性读完,还需要设置什么?
将通信文件描述符设置为非阻塞