Linux服务器--I/O复用(select、poll、epoll)
来源:互联网 发布:手机直播辅助软件 编辑:程序博客网 时间:2024/05/22 13:29
一、select系统调用
1.selectAPI
原型:
#include<sys/select.h>int select(int nfds,fd_set* readfds,fd_set* writefds,fd_set* exceptfds,struct timeval* timeout)
【1】nfds参数指定被监听的文件描述符的总数。
【2】readfds,writefds,exceptfds分别指向可读,可写和异常等事件对应的文件描述符集合。通过这三个参数传入自己感兴趣的文件描述符;select调用返回时,内核将修改它们来通知应用程序哪些文件描述符已经就绪。三个参数都是fd_set结构指针类型:
#include <typesizes.h>#define __FD_SETSIZE 1024#include <sys/select.h>#define FD_SETSIZE __FD_SETSIZEtypedef long int __fd_mask;#undef __NFDBITS#define __NFDBITS (8*(int)sizeof(__fd_mask))typedef struct{#ifdef__USE_XOPEN__fd_maskfds_bits[__FD_SETSIZE/__NFDBITS];#define__FDS_BITS(set)((set)->fds_bits)#else__fd_mask__fds_bits[__FD_SETSIZE/__NFDBITS];#define__FDS_BITS(set)((set)->__fds_bits)#endif}fd_set;
fd_set结构体仅包含一个整型数组,该数组的每个元素的每一位标记一个文件描述符。fd_set能容纳的文件描述符由FD_SETSIZE指定,这就限制了select能同时处理的文件描述符的总量。
由于位操作太繁琐,可以使用下列的宏来访问fd_set结构体中的位:
#include <sys/select.h>FD_ZERO(fd_set *fdset) //清除fdset的所有位FD_SET(int fd, fd_set *fdset) //设置fdset的位fdFD_CLR(int fd, fd_set *fdset) //清除fdset的位fdint FD_ISDET (int fd,fd_set *fdset); //测试fdset的位fd是否被设置
【3】timeout参数用来设置select函数的超时时间。内核将修改它以告诉应用程序select等待了多久。
struct timeval{ long tv_sec; //秒数 long tv_usec; //微秒数};
给timeout变量的两个成员都传递0,则select将立即返回。如果给timeout传递NULL,select将一直阻塞,直到某个文件描述符就绪。
【4】select成功时返回就绪(可读、可写、异常)文件描述符的总数。如果在超时时间内没有任何文件描述符就绪,select将返回0。失败返回-1并设置errno。如果在等待期间程序接收到信号,则select立即返回-1,并设置errno为EINTR.
2.文件描述符就绪条件
【1】socket可读:
- socket内核接收缓存区中的字节数大于或等于其低水位标记SO_RECVLOWAT.
- socket通信的对方关闭连接。此时对该socket的读操作返回0.
- 监听socket上有新的连接请求.
- socket上有未处理的错误.
【2】socket可写:
- socket 内核发送缓存区中的可用字节数大于或等于其低水位标记SO_SNDLOWAT.
socket的写操作被关闭。对写操作被关闭的socket执行写操作将触发一个SIGPIPE信号.
socket使用非阻塞connect连接成功或失败(超时)之后.
socket上有未处理的错误.
网络程序中,select能处理的异常情况只有一种:socket上接收到带外数据
二、poll系统调用
原型:
#include <poll.h>int poll(struct pollfd* fds, nfds_t nfds, int timeout);
【1】fds参数是一个pollfd结构类型的数组,他指定所有我们感兴趣的文件描述符上发生的可读、可写和异常等事件。
struct pollfd{ int fd; //文件描述符 short events; //注册的事件 short revents; //实际发生的事件,由内核填充}
fd成员指定文件描述符;events成员告诉poll监听fd上的哪些事件,它是一系列事件的按位或;revents成员则由内核修改,以通知应用程序fd上实际发生了哪些事件。poll支持的事件类型如下:
通常,应用程序需要根据recv调用的返回值来区分socket上接收的是有效数据还是对方关闭连接的请求,并做相应的处理。GNU为poll系统调用增加了一个POLLRDHUP事件,它在socket上接收到对方关闭连接的请求之后触发。但使用时,需在代码最开始处定义__GNU__SOUREC.
【2】nfds参数指定被监听事件集合fds的大小,其类型定义如下:
typedef unsigned long int nfds_t;
【3】timeout参数指定poll的超时值,单位是毫秒。当timeout为-1时,poll调用将永远阻塞,直到某个事件发生;当timeout为0时,poll调用将立即返回。
poll系统调用的返回值含义与select相同。
三、epoll系列系统调用
1.内核事件表
【1】epoll把用户关心的文件描述符上的事件放在内核里的一个事件表中,所以用一个额外的文件描述符来唯一标识内核中的这个时间表。这个文件描述符使用如下epoll_create函数来创建:
#include<sys/epoll.h>int epoll_create(int size)
size参数现在并不起作用,只是给内核一个提示,告诉它事件需要多大。该函数返回的文件描述符将用作其他所有epoll系统调用的第一个参数,以指定要访问的内核事件表。
【2】操作epoll的内核事件表函数
#include <sys/epoll.h>int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
- fd参数是要操作的文件描述符;
- op参数指定操作类型,有如下三种:
EPOLL_CTL_ADD //往事件表中注册fd上的事件 EPOLL_CTL_MOD //修改fd上的注册事件EPOLL_CTL_DEL //删除fd上的注册事件
- event参数指定事件,是epoll_event结构指针类型
struct epoll_event { uint32_t events; //epoll事件 epoll_data_t data; //用户数据};
- events成员描述事件类型。epoll支持的事件类型和poll基本相同,标识epoll 事件类型的宏是在poll对应的宏前加上“E”。epoll还有两个额外的事件类型——-EPOLLET和EPOLLONESHOT。
- data成员用于存储用户数据,其类型epoll_data_t定义:
typedef union epoll_data{ void *ptr; int fd; uint32_t u32; uint64_t u64; } epoll_data_t;
epoll_ctl成功时返回0,失败返回-1,并设置errno。
2.epoll_wait函数
在一段超时时间内等待一组文件描述符上的时间
原型:
#include<sys/epoll.h>int epoll_wait(int epfd,struct epoll_event* events,int maxevents,int timeout);
成功时返回就绪的文件描述符的个数,失败返回-1并设置errno
- timeout与poll借口的timeout参数含义相同。
- maxevents参数指定最多监听多少个事件,必须大于0.
- epoll_wait检测到事件,就将所有就绪的事件从内核表中复制到它第二个参数events指向的数组中。这个数组只用于输出epoll_wait检测到的就绪事件。
poll和epoll在使用上的区别
poll:int ret = poll(fds, MAX_EVENT_NUMBER, -1);for (int i = 0; i < MAX_EVENT_NUMBER; ++i) //必须遍历一遍已注册的文件描述符{ if (fds[i].revents&POLLIN) { int sockfd =fds[i].fd; //处理sockfd }}
epoll:int ret = epoll_wait(epollfd, events, MAX_EVENT_NUMBER, -1);for (int i = 0; i < ret; i++) //只需遍历就绪的ret个文件描述符 int sockfd = events[i].data.fd; //处理sockfd }}
3.LT/ET模式
【1】epoll对文件描述的操作有两种模式:LT(Level Trigger, 电平触发)模式和ET(Edge Trigger, 边沿触发)模式。
【2】默认工作模式为LT模式,当往epoll内核事件表中注册一个文件描述符上的EPOLLET事件时,epoll就以ET模式来操作该文件描述符。ET模式是epoll的高效工作模式。
【3】LT模式的文件描述符,当epoll_wait检测到其上有事件发生并通知应用程序后,应用程序可以不立即处理该事件。这样,当应用程序下一次调用epoll_wait时,epoll_wait还会再次向应用程序通告此事件,直到该事件被处理。而ET模式下,当epoll_wait检测到其上有事件发生并通知应用程序后,应用程序必须立即处理该事件,后续将不再向应用程序通知。ET模式在很大程度上降低了同一个epoll事件被触发的次数
LT/ET模式区别代码
运行上面的代码,传输超过10字节大小的数据,结果如下:
LT模式
ET模式
4.EPOLLONESHOT模式
即使是ET模式下一个socket上某个事件还是可能被触发多次,比如一个线程在读取完socket上数据后去处理数据时,又有新数据可读,此时就会有另一个线程来读取这些数据,于是现在就是两个线程同时操作一个线程,这种情况就可以用EPOLLONESHOT事件处理
对于注册了EPOLLONESHOT事件的文件描述符,操作系统最多触发其上注册的一个可读、可写或异常事件,且只触发一次,除非使用epoll_ctl重置该文件描述符上注册的EPOLLONESHOT事件。
所以注册了EPOLLONESHOT事件的socket,被一个线程处理完后就要立即重置这个socket上的EPOLLONESHOT事件。
- Linux服务器--I/O复用(select、poll、epoll)
- Linux I/O复用:select ,poll,epoll
- linux I/O复用select、poll和epoll
- linux 网络编程 I/O复用 select,poll ,epoll
- 浅谈I/O复用:select、poll、epoll
- I/O复用 select poll epoll
- I/O复用select、poll、epoll
- I/O多路复用(select、poll、epoll)
- 服务器编程——I/O复用(select、poll、epoll)
- I/O复用(select、poll、epoll模型)
- select , poll , epoll I/O Multiplexing(I/O多路复用)
- I/O复用(I/O multiplexing): select, pselect, poll, ppoll, epoll
- Linux I/O多路复用之select,poll与epoll区别
- Linux I/O多路复用之select,poll与epoll区别
- Linux下的I/O多路复用select,poll,epoll浅析
- Linux下的I/O多路复用select,poll,epoll浅析
- 三种 I/O 复用(select poll epoll)的优缺点总结 & epoll 为何如此高效
- I/O复用:select、poll、pselect和epoll
- cocos js Spine sp.SkeletonAnimation
- 2017多校四 1011题 hdu 6077 Time To Get Up 感谢数电老师(。
- 编程练习3
- 分布式架构真正适用于大型互联网项目的架构 dubbo+zookeeper+springmvc+mybatis+shiro+redis
- SpringMVC4.3x教程之七国际化的三种实现详解
- Linux服务器--I/O复用(select、poll、epoll)
- PHP 循环 之 While 循环方法的使用
- 1976-函数训练之被甩
- HDU1698 Just a Hook_线段树
- BW:传输到Open Hub的DTP,怎么删除?
- Android常用网站
- keras 画训练过程曲线
- 培训班出身的程序员为什么遭人嫌弃
- shell 脚本编程之函数