//头文件
#include <sys/epoll.h>
//创建epoll实例
int epfd = epoll_create(>0);//成功返回的是文件描述符错误返回的是-1
//在epoll实例中添加需要检测的节点,
struct epoll_event ev;
ev.events=EPOLLIN;//检测lfd的读事件(基础有三个都是对应文件描述符的事件(读事件、写事件、错误事件)man epoll_ctl可以看到)
ev.data.fd=lfd;//要操作的文件描述符 这个其实设计的联合体 有别的可以选 看man
//使用epoll_ctl操作epoll实例
/*
EPOLL_CTL_ADD:注册新的 fd
EPOLL_CTL_MOD:修改已注册的 fd
EPOLL_CTL_DEL:删除 fd
*/
if (epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev) == -1) {
perror("epoll_ctl: add");
exit(EXIT_FAILURE);
}
//循环等待事件发生
int epoll_wait(int epfd,struct epoll_event *events,int maxevents,int timeout);//通常在while包装下
//timeout 设置-1表示无线等待
epoll默认是水平模式(LT模式),只提示一次的边沿模式(ET模式)更高效。
水平模式:只要检测的文件描述符事件缓冲区有数据就会epoll_wait阻塞;
边沿模式:当对应的文件描述符被放到epoll检测中的事件,只有有新的数据到达缓冲区才会epoll_wait解除阻塞。
(只会通知一次,不会管缓冲区的数据是否有被读出)
//边沿模式的设置(默认就是水平模式)
ev.events=EPOLLIN|EPOLLET;
//因为只通知一次就需要一次性将所有的数据都处理完毕
//方法是开辟足够大的缓冲区(在内存上)或者循环接收
//二者都是有弊端的,一个是占用的内存可能过大
//另一个是默认的套接字通信中的read/write等相关函数都是阻塞的
//也就是说当我们不知道缓冲区有多少数据,我们一直recv,直到缓冲区为空,缓冲区会阻塞等待(这个线程就会阻塞的)
//所以需要修改这个文件描述符的属性,是其是非阻塞的
修改文件描述符的属性,是其是非阻塞的
#include <fcntl.h>
//这里cfd是要操作的文件描述符
int flag = fcntl(cfd,F_GETFL);//F_GETFL意思是获取到当前文件描述符的属性
flag |=O_NONBLOCK;//添加非阻塞属性
fcntl(cfd,F_SETFL,flag);
也可以使用
rt = fcntl(m_tickleFds[0], F_SETFL, O_NONBLOCK);
但这种方式会覆盖所有其他标志(如果前面有添加别的属性的话)
fcntl函数讲解
或者看man文档
还没完...
设置为非阻塞后,当缓冲区为空后第一次读会读出来空
第二次就会出现错误:
rec error: Resource temporarily unavailable
man recv
/return value (man文档搜索这个)
如果是EAGAIN就代表缓冲区已经读完了然后我们就可以break了
#include <errno.h>
if(errno==EAGAIN)
{
break;
}else
{
perror/assert 看需求
}