将检测文件描述符的变化委托给内核去处理,然后内核将发生变化的文件描述符对应的事件返回给应用程序。
更多技术文档参见: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 { 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返回一次的情况下读完数据? 循环读数据,直到读完数据,但是读完数据后会阻塞 若能一次性读完,还需要设置什么? 将通信文件描述符设置为非阻塞进阶epoll