栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

selcet/poll/epoll相关知识

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

selcet/poll/epoll相关知识

selcet/poll/epoll相关知识 基础知识

多路复用器: 一种IO复用技术可以让一个进程同时为多个客户端端提供服务,减少了系统调用次数。常见三种:select、poll和epoll。
wakeup callback机制: 这是IO多路复用机制存在的本质。Linux通过socket睡眠队列来管理所有等待socket的某个事件的process,同时通过wakeup机制来异步唤醒整个睡眠队列上等待事件的process,通知process相关事件发生。通常情况,socket的事件发生的时候,其会顺序遍历socket睡眠队列上的每个process节点,调用每个process节点挂载的callback函数。在遍历的过程中,如果遇到某个节点是排他的,那么就终止遍历,总体上会涉及两大逻辑:(1)睡眠等待逻辑;(2)唤醒逻辑。

多路复用器原理 select :
int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);
select参数含义:
nfds: 文件描述符个数。
struct fd_set: 存放文件描述符(file descriptor)的集合,包括:可读,可写,发生异常三种状态。
struct timeval: 等待的时间。
select原理:
fd_set: fd_set中的每一bit可以对应一个文件描述符fd,1字节长的fd_set最大可以对应8个fd
返回值: 成功时:返回三中描述符集合中准备的文件描述符数量;超时:返回0;错误:返回-1。
select总结:
select多路复用器是采用 轮询方式,一直在轮询所有的相关内核进程,查看他们的进程状态。若已经就绪(该就绪队列底层由 数组实现),则马上将该内核进程放入到就绪队列。否则,继续查看下一个内核进程状态。在处理内核进程事务之前,app进程首先会从内核空间中将用户连接请求相关数据复制到用户空间。
select缺陷:
⭐对所有内核进程采用轮询方式效率会很低。因为对于大多数情况下,内核进程都不属于就绪状态,只有少部分才会是就绪态。所以这种轮询结果大多数是毫无意义的。
⭐由于就绪队列底层由数组实现,所以其所能处理的内核进程数量是由限制的,即其能够处理的最大并发连接数是有限制的。
⭐从内核空间到用户空间的复制,系统开销大。
poll :
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
struct pollfd{
	int fd;			//文件描述符
	short events;	//等待的事件
	short revents;	//实际发生的事件
};
poll参数含义:
fds: 指向一个结构体数组的第0个元素的指针,每个数组元素都是一个struct pollfd结构,用于指定测试某个给定的fd的条件。
fd: 每一个 pollfd 结构体指定了一个被监视的文件描述符,可以传递多个结构体,指示 poll() 监视多个文件描述符。
fds: 指定监测fd的事件(输入、输出、错误),每一个事件有多个取值。
events: 存放文件描述符(file descriptor)的集合,包括:可读,可写,发生异常三种状态。
revents: revents 域是文件描述符的操作结果事件,内核在调用返回时设置这个域,events 域中请求的任何事件都可能在 revents 域中返回。
nfds: 用来指定第一个参数数组元素个数。
timeout: 指定等待的毫秒数,无论 I/O 是否准备好,poll() 都会返回.
poll原理:
fd_set: fd_set中的每一bit可以对应一个文件描述符fd,1字节长的fd_set最大可以对应8个fd
返回值: 成功时:poll() 返回结构体中 revents 域不为 0 的文件描述符个数;超时:返回0;错误:返回-1。
poll与select区别:
其就绪队列由链表实现;
对于要处理的内核进程数量理论上是没有限制。
select缺陷:
poll并没着手解决性能问题,poll只是解决了select的问题fds集合大小1024限制问题。
epoll :

epoll的接口非常简单,一共就三个函数:
⭐epoll_create:

int epoll_create(int size);
epoll_create函数:
size: 必须设置一个大于0的值。
返回值: 调用成功返回一个非负值的文件描述符pollfd,调用失败返回-1。

⭐epoll_ctl:

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

poll_event:

struct epoll_event {
    uint32_t     events; // 需要检测的fd事件,取值与poll函数一样
    epoll_data_t data; // 用户自定义数据
};

typedef union epoll_data {
    void    *ptr;
    int      fd;
    uint32_t u32;
    uint64_t u64;
} epoll_data_t;
epoll_ctl函数:
epfd: 调用epoll_create函数创建的pollfd。
op: 表示向epollfd上添加、修改或移除一个其他fd。(EPOLL_CTL_ADD、EPOLL_CTL_MOD、EPOLL_CTL_DEL)
fd: 即需要被操作的fd。
event: 是一个epoll_event结构体的地址。
返回值: 调用成功返回0,调用失败返回-1。

⭐epoll_wait

int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
epoll_wait函数:
epfd: 调用epoll_create函数创建的epollfd。
event: 是一个epoll_event结构数组的首地址,这是一个输出参数,函数调用成功后,events中存放的是与就绪事件相关epoll_event结构体数组。
maxevents: 数组元素的个数。
timeout: 超时时间,单位是毫秒,如果设置为0,epoll_wait会立即返回。
返回值: 调用成功会返回有事件的fd数目;如果返回0表示超时;调用失败返回-1。

epoll在被内核初始化时(操作系统启动),同时会开辟出epoll自己的内核高速cache区,用于安置每一个我们想监控的socket。这些socket会以红黑树的形式保存在内核cache里,以支持快速的查找、插入、删除。

poll与select区别:
⭐epoll多路复用器是对select与poll的增强与改进,其不再采用轮询方式,而是采用 回调方式实现对内核进程状态的获取;
⭐一旦内核进程就绪,其就会回调epoll多路复用器,进入到多路复用器的就绪队列(由 链表实现);
⭐应用程序所使用的数据,也不再从内核空间复制到用户空间了,而是使用mmap (是指文件/对象的内存映射,被映射到多个内存页上)零拷贝机制,所以同一块内存(共享内存)就可以避免这个问题,大大降低了系统开销。

epoll 一定要加定时器

LT模式和ET模式

select()、poll()模型都是水平触发模式 (LT),epoll()模型即支持水平触发,也支持边缘触发 (ET),默认是水平触发。边缘触发 是指每当状态变化时发生一个io事件, 条件触发 是只要满足条件就发生一个io事件。
** LT:** 默认/缺省的工作方式,支持 block 和 no_block socket,这种工作方式下,内核会通知你一个 fd 是否就绪,然后才可以对这个就绪的 fd 进行I/O操作。就算你没有任何操作,系统还是会继续提示 fd 已经就绪,不过这种工作方式出错会比较小。(水平触发,只要有数据可以读,不管怎样都会通知)
** ET:** 高速工作方式 ,仅支持 no_block socket,这种工作方式下,当 fd 从未就绪变为就绪时,内核会通知 fd 已经就绪,并且内核认为你知道该 fd 已经就绪,不会再次通知了,除非因为某些操作导致fd就绪状态发生变化。如果一直不对这个 fd 进行I/O操作,导致 fd 变为未就绪时,内核同样不会发送更多的通知,因为 only once。所以这种方式下,出错率比较高,需要增加一些检测程序。(边缘触发,只有状态发生变化时才会通知,可以理解为电平变化)

总结:
1.对于监听的sockfd,最好使用水平触发模式,边缘触发模式会导致高并发情况下,有的客户端会连接不上。如果非要使用边缘触发,网上有的方案是用while来循环accept()。

2.对于读写的connfd,水平触发模式下,阻塞和非阻塞效果都一样,不过为了防止特殊情况,还是建议设置非阻塞。

3.对于读写的connfd,边缘触发模式下,必须使用非阻塞IO,并要一次性全部读写完数据。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1013179.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号