I/O模式提供了一种机制,当一个或多个I/O条件满足时,可以将一个输入操作分为两个不同的阶段,I/O模式分为5中不同的类型,即:阻塞I/O,非阻塞I/O,I/O复用,信号驱动I/O和异步I/O。
函数:int select(int masfd,fd_set *readset,fd_set *writeset,
fd_set *exceptset,const struct timeval *timeout);
头文件:sys/select.h sys/time.h
说明:该函数允许进程指示内核等待多个时间中的任意个发生,并在一个或多个事件发生或经过指定时间才唤醒进程其中timeeval结构如下:
struct timeval{
long tv_sec;//秒
long tv_usec;//微秒
};
timeout函数中起到定时器的作用,其取值含义如下:
取0:相当于非阻塞模式,也就是不用等待,,检查完描述字后立即返回,使用该方法可以有效的轮询集合中的所有文件描述字;
取NULL:将等待,直到有一个描述字准备好后I/O返回;
取设定值:相当于一般的定时器,在描述字准备好I/O或超过了指定时间后才返回。
readset、writeset和exceptset为3个文件描述字集合,select监视集合中定义的描述字,如果不需要监视,可以设定为NULL指针。
关于返回值:
select调用返回时,除了那些已经就绪的描述符外,select将清除readfds、writefds和exceptfds中的所有没有就绪的描述符。select的返回值有如下情况: |
|||||
1.正常情况下返回就绪的文件描述符个数; |
|||||
2.经过了timeout时长后仍无设备准备好,返回值为0; |
|||||
3.如果select被某个信号中断,它将返回-1并设置errno为EINTR。 |
|||||
4.如果出错,返回-1并设置相应的errno。
|
宏FD_SET设置文件描述符集fdset中对应于文件描述符fd的位(设置为1);
宏FD_CLR清除文件描述符集fdset中对应于文件描述符fd的位(设置为0);宏FD_ZERO清除文件描述符集fdset中的所有位(既把所有位都设置为0);
宏FD_ISSET来检测文件描述符集fdset中对应于文件描述符fd的位是否被设置。
函数poll提供了和select相似的功能,它可以将套接口设置为非阻塞模式。其和select不同点在于,poll没有使用3个基于位的文件描述符集合,而是采用了pollfd数组。
函数:int poll(struct pollfd *fdarray,nfds_t nfds,int timeout);
头文件:poll.h
说明:成功时返回描述字的个数,如果超时,返回0,如果出错,返回-1。并设置errno的值为如下值之一:
EBADF:一个或多个结构体中指定的文件描述符无效;
EFAULT:fds指针指向的地址超出进程指定的地址空间;
EINTR:请求的事件之前产生一个信号,调用可以重新发起;
EINVAL:nfd参数超出PLIMIT_NOFILE的值;
ENOMEM:可用内存不足,无法完成请求。
其中struct pollfd结构如下:
struct pollfd{
int fd;
short events;
short revents;
}
其中,event域是监视该文件描述符的掩码,有用户设置,revents域是文件描述符的操作结构掩码,有内核设定。Events域请求的任何事件都可以在revents域中返回,合法事件如下:
POLLIN:有数据可读;
POLLRDNORM:有普通数据可读(不常用);
POLLRDBAND:有优先数据可读;
POLLPRI:有紧迫数据可读;
POLLOUT:学数据不会导致阻塞;
POLLWRNORM:写普通数据不会导致阻塞;
POLLWRBAND:写优先数据不会导致阻塞;
POLLMSG:SIGPOLL消息可用;
此外,revents也可返回如下事件:
POLLER:指定的文件描述符发生错误;
POLLHUP:指定的文件描述符挂起事件;
POLLNVAL:指定的文件描述符非法;
POLLIN=POLLRDNORM|POLLRDBAND
POLLOUT=POLLWRNORM
POLLIN|POLLPRI=select的读
POLLOUT|POLLWRBAND=select的写。
对于函数的timeout参数,情况如下:
大于0:指定等待多长时间;
等于0:立即返回;
为INFTIM:(该值为-1,有些系统定义在poll.h里,有些定义在sys/stropts.h 里,有些没有定义,需要自己定义)表示永远等待。
在linux2.6内核以及以上版本上增加了epoll机制,它包含用于处理I/O事件多路分离的一组函数。它在一定程度上弥补了linux内核对异步I/O支持的不足,epoll机制加上非阻塞的I/O可以模拟实习那异步I/O。
epoll机制所使用的数据结构:
typedef union epoll_data{
void *ptr;
int fd;
__uint32_t u32;
__uint64_t u64;
} epoll_data_t;
struct epoll_event{
__uint32_t events;
epoll_data_t data;
}
Epoll_event用于注册所感兴趣的事件和回传所发生待处理的事件,其中epoll_data联合体用来保存触发事件的某个文件描述符的数据。Epoll_event结构中的events字段表示感兴趣事件和触发的事件,其取值为:
EPOLLIN:表示对于的文件描述符可读;
EPOLLOUT:表示对应的文件描述符可写;
EPOLLPRI:表示对应的文件描述符有紧急的数据可读;
EPOLLERR:表示对于的文件描述符发生错误;
EPOLLHUP:表示对应的文件描述符被切断;
EPOLLET:表示对应的文件描述符有事件发生
函数(1):epoll_create(int size);
头文件:sys/epoll.h
说明:该函数生成一个epoll专用的文件描述符,其中的参数为指定内核分配size个相关内核对象。
函数(2):epoll_ctl(int epfd,int op,int fd,struct epoll_event *event);
头文件:sys/epoll.h
说明:用于控制某个文件描述符上的时间,可以注册,修改,删除时间,其中epfd为有epoll_create生成的epoll专用文件描述符,op为要进行的操作,取值为:EPOLL_CTL_ADD(注册),EPOLL_CTL_MOD(修改),EPOLL_CTL_DEL(删除);fd为关联的文件描述符,event为指向epoll_event的指针,调用成功返回0,失败返回-1。
函数(3):
epoll_wait(int epfd,struct epoll_event *events,int maxevents,int timeout);
头文件:sys/epoll.h
说明:用于轮询I/O时间的发生。其中,epfd为epoll_create生成的epoll描述符,epoll_event为用于回传代理事件的数组。maxevents为每次能处理的事件数,timeout为等待I/O事件发生的超时值。
l 支持一个进程打开大数目的socket描述符
l IO效率不随FD数目增加而线性下降