阻塞和非阻塞主要是指这个函数,是否会导致我们这个进程进入sleep休眠。
阻塞:这种函数,会导致进程进入休眠,在等待一个动作发生才会继续走下去,这种阻塞不好,效率很低
不会卡住,充分利用CPU时间片,不断的调用accept和recvfrom函数来查看有没有数据到来,通过标记来进行判断,如果数据到来,那么就会卡着,将内核缓存区的数据拷贝到用户缓存区。
调用一个异步I/O函数,要给这个函数指定一个缓存区,还需要一个回调函数,其他事情交给操作系统,调用完一个异步I/O函数会立即返回,操作系统会判断数据是否到来,来了就会将数据拷贝到缓存区中,调用指定回调函数来通知你。
和非阻塞的差别:需要不停的调用I/O函数,如果数据来就会卡在I/O函数这,就会将数据从内核缓存区复制到用户缓存区,异步I/O不需要不停的调用,只需要调用一次,然后可以去执行其他事情,通过内核检查数据是否到来,在整个过程中没有卡顿
1、select先判断数据有没有,没数据卡在那里,有数据返回之后,用recvfrom去读取数据(还是会卡一下,取数据的时候,将内核缓存区拷贝到用户缓存区),更麻烦,需要调用两个函数才能拿到数据,所谓I/O复用,就是我可以同步等待多个socket的数据,任意一个socket上面有数据了我就去recvfrom去读
1、int epoll_create(int size);
参数:
size 创建的红黑树的监听数据节点(数目最大有多大,从Linux 2.6.8开始,max_size参数将被忽略,但必须大于零。)
返回值:
成功 指向新创建的红黑树的根节点fd
失败 -1 errno
作用:创建一颗空红黑树和一个双向空链表
流程:
1、开辟了一块eventpoll结构类型的内存
结构中成员rbr指向,一颗红黑树的根节点
结构中成员rdlist指向,双向链表的头指针
2、int epoll_ctl(int epfd,int op,int fd,struct epoll_event* event);
参数:
epfd: epoll_create 函数的返回值
op: 对该监听的红黑树操作
EPOLL_CTL_ADD 添加fd到 监听红黑树
EPOLL_CTL_MOD 修改fd在监听红黑树上的监听事件
EPOLL_CTL_DEL 将一个fd从监听红黑树上摘下(取消监听)
fd:待监听的fd文件描述符
event:结构体的地址
struct epoll_event {
uint32_t events;
// EPOLLIN / EPOLLOUT / EPOLLERR
epoll_data_t data;
// fd 对应监听事件的fd
// void* ptr
// u32
// u64
};
typedef union epoll_data {
void *ptr;
int fd;
uint32_t u32;
uint64_t u64;
} epoll_data_t;
返回值:
成功 0
失败 -1 errno
作用:把一个socket以及这个socket相关的事件添加到epoll对象描述符中,目的通过epoll来监听这个socket,有感兴趣的事件来了通知我们
流程:
1、EPOLL_CTL_ADD 添加
生成红黑树的节点,epitem结构体,将socket保存到节点中、作为红黑树的key,添加的事件也保存进去
成员:rbn结构体包含三个指针,左、右、父节点的指针
成员:rblist结构体包含:指向前一个元素,后元素的指针
2、EPOLL_CTL_DEL 删除
a)通过socket到红黑树中进行查找,
b)有就把这个节点删除
3、EPOLL_CTL_DEL 修改
a)通过socket到红黑树中进行查找
b)找到红黑树节点修改红黑树事件
int epoll_wait(int epfd,struct epoll_event* events,int maxevents,int timeout);
参数:
epfd:epoll_create 函数返回值 epfd
events:传出参数【数组】,满足监听条件的
maxevents:数组 元素的总个数1024
timeout:毫秒
-1 阻塞
0 不阻塞
>0 超时事件(毫秒)
返回值:
>0 满足监听的总个数,可以用作循环上限
0 没有fd满足条件
-1 errno
作用:阻塞一小段时间,等待事件发生,返回事件集合,也就是获取内核的事件通知(遍历双向链表,把双向链表数据拷贝出去,拷贝完毕,移除)
总结:红黑树的节点是通过EPOLL_CTL_ADD添加进去的。
一般用四种情况,操作系统会把节点添加到红黑树上:
1、客户端完成三次握手,服务端要accept()
2、客户端关闭连接时候,服务器调用close()
3、到客户端发送数据,服务器调用read()
4、当可以发送数据时,服务器调用write()
# 查看有哪些进程监听80端口
lsof -i:80