栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

linux系统调用函数之select、poll、epoll

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

linux系统调用函数之select、poll、epoll

1. select函数 1.1 相关函数说明
int select(int nfds, fd_set *readfds, fd_set *writefds,
			fd_set *exceptfds, struct timeval *timeout);
  • 返回值:
  • nfds:监控的文件描述符集里的最大文件描述符+1,此参数告诉内核监测前多少个文件描述符的状态
  • readfds:传入传出参数,位图
    • 传入时:代表要监听的哪些文件描述符的可读事件
    • 传出时:代表哪些文件描述符实际发生了可读事件
  • writefds:传入传出参数,位图
    • 传入时:代表要监听哪些文件描述符的可写事件
    • 传出时:代表文件描述符哪些实际发生了可写事件
  • exceptfds:传入传出参数,位图
    • 传入时:代表要监听哪些文件描述符的异常事件
    • 传出时:代表哪些文件描述符实际发生了异常事件
  • timeout:设置阻塞时间
    • NULL:永久等下去
    • 设置timeval,等待固定时间
    • 设置timeval里时间均为0,表示检查描述字后立即返回,轮询。
  • 返回值:
    • 成功:返回所监听的所有监听集合中,满足条件的总数。
struct timeval {
	long tv_sec; 
	long tv_usec; 
};
  •  设置监听集合的函数
void FD_CLR(int fd, fd_set *set); 	//将fd从文件描述符集合中清除
int FD_ISSET(int fd, fd_set *set); 	//判断fd是否在文件描述符集合中
void FD_SET(int fd, fd_set *set); 	//将fd加入文件描述符集合中
void FD_ZERO(fd_set *set); 			//把文件描述符集合里所有位清0
1.2 原理
  • 用户进程调用系统调用函数select,会进入阻塞状态,然后内核帮我们轮询我们要监听的socket接口,当有我们需要的事件发生后就会返回。
  • 返回值代表有多少个满足的事件发生了。
  • 然后我们根据传出参数找到哪些事件发生了,并对其做相应的处理。
1.3 特点
  • 单个进程可监控的fd数量被限制,即能监控的端口的大小有限。32位机器默认是1024个
  • 返回值只告诉我们有多少满足事件发生了,至于是哪个socket发生了满足事件,需要我们去挨个遍历那三个文件描述符集合才能找出。
  • select函数的三个文件描述符参数是传入传出参数,值被反复修改,不太方便。
2. poll函数 2.1 相关函数说明
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
  • fds:结构体pollfd数组的首地址
  • nfds:fds数组里面的元素个数
  • timeout:设置阻塞时间
    • -1:阻塞等待
    • 0:立刻返回,不阻塞进程
    • >0:等待指定毫秒数
struct pollfd {
	int fd; 
	short events; 
	short revents; 
};
  •  fd:文件描述符
  • envents:对该文件要监控的事件,常见的可选项:
    • POLLIN:表示监控读事件
    • POLLOUT:表示监听写事件
    • POLLERR:表示监听异常事件
  • revents:该文件所监听事件中满足条件返回的事件
2.2 原理
  • 本质与select区别不大。它将用户传入的pollfd数组拷贝到内核空间,然后内核轮询每个要监听的fd对应的设备状态。
  • 返回的也是有多少个设备准备就绪,然后用户进程遍历pollfd数组,找到准备就绪的socket进行处理
  • poll返回后,需要对pollfd数组中的每个元素检查其revents值,来确定是否有满足事件发生。
2.3 特点:
  • 突破监听文件描述符最大上线为1024
  • 监听集合与返回集合分离。
  • 搜索返回结果范围变小(只需要遍历所指定要监听的文件描述符)
3. epoll 3.1 相关函数说明
int epoll_create(int size);
  • 函数说明:创建一个epoll句柄,
  • size:指明内核监听的文件描述符的个数,是个建议值
  • 返回值:
    • 成功:epoll句柄,指向一颗红黑树的树根。
    • 失败:-1,设置errno
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
  • 函数说明:控制某个epoll监听的文件描述符的事件:注册、修改、删除
  • epfd:epoll句柄
  • op:操作:
    • EPOLL_CTL_ADD:注册新的fd到epfd
    • EPOLL_CTL_MOD:修改已经注册的fd的监听事件
    • EPOLL_CTL_DEL:从epfd中删除一个fd
  • fd:文件描述符
  • event:结构体,要监听的事件。(结构体的地址)
struct epoll_event {
	__uint32_t events; 
	epoll_data_t data; 
};

typedef union epoll_data {
	void *ptr;
	int fd;
	uint32_t u32;
	uint64_t u64;
} epoll_data_t;

  • events常用可选项
    • EPOLLIN:表示对应的文件描述符可以读
    • EPOLLOUT:表示对应的文件描述符可以写
    • EPOLLERR:表示对应的文件描述符发生错误
  • ptr:泛型指针。表示可以传任意类型的数据,包括结构体。
    • 设置时,通过传入一个结构体,在结构体内部定义函数。可以实现指定监听事件的指定回调。
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout)
  • 函数说明:等待所监控的文件描述符上有事件产生,类似select()调用
  • epfd:epoll句柄
  • events:传出参数,要监听的事件集合(数组)
  • maxevents:告之内核这个events这个集合大小。maxevents的值不能大于epoll_create()时的size
  • timeout:超时时间
    • -1:阻塞
    • 0:立即返回,非阻塞
    • >0:指定毫秒
  • 返回值
    • 成功:返回有多少个文件描述符就绪
    • 时间到时:返回0
    • 出错:返回-1
3.2 原理
  • 先执行epoll_create,创建了一颗红黑树,将句柄返回。该红黑树上的每一个节点都代表要监听的事件。
  • 通过执行epoll_ctl函数,将要监听的事件注册到红黑树上去。
  • 最后调用epoll_wait函数,进行实际的监听。
3.3 特点
  • 返回的结构体数组中代表出现了监听事件的文件描述符。所以不用轮询所有的监控文件描述符。
3.4 epoll的两种触发模式
  • 水平触发(LT):
    • 当被监听的文件描述符上有可读写事件发生时,epoll_wait会通知处理程序去读写。如果这次没有把数据一次性全部读写完(比如内核缓冲区来了1000字节,应用程序只读了500字节)。那么下次调用epoll_wait时,它还会通知你在上次没有读完的文件描述符上继续读写。
    • select、poll都是只支持水平触发模式。epoll默认水平触发,也支持边缘触发
  • 边缘触发(ET):
    • 当当被监听的文件描述符上有可读写事件发生时,epoll_wait()会通知处理程序去读写。如果这次没有把数据全部读写完,那么下次调用epoll_wait()时,它不会通知你,也就是它只会通知你一次,直到该文件描述符上出现了第二次可读写事件才会通知你。
    • 如何设置边缘触发:event.events=EPOLLIN|EPOLLET;

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

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

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