内容简介:IO复用:让进程等待一系列IO条件而不是一个IO条件通过定义:
IO复用:让进程等待一系列IO条件而不是一个IO条件
通过 select
和 poll
函数我们可以同时监听多个描述符,在描述符就绪时进行对应的操作。
select
定义:
//maxfdpl: 待测试的描述符个数 //返回就绪描述符的个数,若超时则为0, 若出错则为-1 int select(int maxfdpl, fd_set *readset, fd_set *writeset, fd_set *exceptset, struct timeval *timeout); //超时选项 //NULL:wait forever;0:don't wait struct timeval { long tv_sec; /* seconds */ long tv_usec; /* and microseconds */ }; //每个fds_bit的每一位对应一个描述符 typedef struct fd_set { int fds_bits[FD_SETSIZE/sizeof(int)/NBBY]; /* NBBY=bits in a byte ; usually 8*/ } fd_set; #define FD_SETSIZE 1024 /* fd_set中描述符的总数 */ void FD_ZERO(fd_set *fdset); /* clear all bits in fdset */ void FD_SET(int fd, fd_set *fdset); /* turn on the bit for fd in fdset */ void FD_CLR(int fd, fd_set *fdset); /* turn off the bit for fd in fdset */ void FD_ISSET(int fd, fd_set *fdset); /* is the bit for fd on in fdset ? */ 复制代码
select的使用方法:
int fds[FD_SETSIZE]; 保存当前所有描述符 fd_set rset, wset, eset; //定义读、写、异常对应的fd_set //初始化fd_set,非常重要且不能省略,因为如果不初始化可能会影响FD_ISSET的调用结果 FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&eset); for (;;) { //在循环中调用select select(FD_SETSIZE, &rset, &wset, &eset, NULL); //遍历当前所有的fd,处理就绪的fd for (int i = 0; i < FD_SETSIZE; i++) { if (FD_ISSET(fds[i], &rset)) { //handle read } if (FD_ISSET(fds[i], &wset)) { //handle write } if (FD_ISSET(fds[i], &eset)) { //handle exception } } } 复制代码
fd_set的限制
在很早之前就看到网上的介绍说select在描述符个数上是有限制的,现在终于知道这个限制是从哪来的了,这实际上跟fd_set的实现机制有关。
fd_set
中使用int数组中的各个位来保存多个描述符的状态,这个数组称为 描述符集
,比如数组的第一个数有32位,那么第一个数的每一位就表示第0~31个描述符的状态,这样一来当我们调用 FD_ISSET
来判断某一个描述符状态时,我们只需要找到其对应的位判断其是0或者1就行了;同理当我们需要设置某个描述符状态时,只需要设置对应的位的状态即可。而 fd_set
中数组的大小是通过 FD_SETSIZE
这个值算出来的, FD_SETSIZE
是一个宏定义,通常它的默认值比较小,在我的mac上查看其默认值是1024,也就是说在我的mac上select能够支持的最大的描述符数量是1024个。当然 FD_SETSIZE
也可以重新定义,但如果要调整需要重新编译内核。
描述符读就绪条件
- 接收缓冲区数据字节数大于低水位(默认是1),这时读取操作返回大于0
- 读半关闭,也就是对端发来了FIN,这时返回0,也就是EOF
- 当前套接字是监听套接字,而且已完成连接数不为0,这时可以进行accept操作
- 描述符上有套接字错误需要处理
描述符写就绪条件
- 发送缓冲区数据字节数大于低水位(通常为2048);
- 套接字已连接或不需要连接(UDP)
-
写半关闭,这时如果再写会收到
SIGPIPE
信号 -
使用非阻塞式
connect
的套接字已建立连接或者connect
失败 - 描述符上有套接字错误需要处理
shutdown&close
有两个函数可以关闭套接字: shutdown
和 close
,它们的区别如下:
-
close
会将引用计数减1,当计数为0时关闭套接字;shutdown
可以直接触发关闭。 -
close
会终止读和写两个方向;shutdown
可以通过参数howto
指定关闭某个方向
int close(int fd); int shutdown(int fd, int howto); /* * howto arguments for shutdown(2), specified by Posix.1g. */ #define SHUT_RD 0 /* shut down the reading side */ #define SHUT_WR 1 /* shut down the writing side */ #define SHUT_RDWR 2 /* shut down both sides */ 复制代码
poll
poll
和 select
的功能类似,也支持IO复用,但是 poll
没有使用描述符集,而是使用 pollfd
这种结构来表示描述符的状态。
//nfds:array的长度,受进程能打开的最大文件数限制 //返回就绪描述符的个数,若超时则为0, 若出错则为-1 int poll(struct pollfd *fdarray, unsigned long nfds, int timeout); struct pollfd { int fd; /* descriptor to check */ short events; /* events of intrests on fd */ short revents; /* events that occurred on fd */ }; 复制代码
poll
的使用方法:
struct pollfd pollfds[OPEN_MAX]; //定义pollfd数组,将需要监听的描述符保存起来 for (;;) { //在循环中调用poll poll(pollfds, OPEN_MAX, INFTIM); for (int i = 0; i < OPEN_MAX; i++) { //遍历pollfd数组处理就绪的描述符 struct pollfd pfd = pollfds[i]; if (pfd.revents & POLLIN) { //handle read } if (pfd.revents & POLLOUT) { //handle write } } } 复制代码
poll
识别的数据类型:普通(normal)、优先级带(priority band)、高优先级(high priority);
这些术语来自基于流的实现。(没太明白,先标记下)
events常量列举:
常量 | 出现在events | 出现在revents | 说明 |
---|---|---|---|
POLLIN | y | y | 普通或优先级带数据可读 |
POLLRDNORM | y | y | 普通数据可读 |
POLLRDBAND | y | y | 优先级带数据可读 |
POLLPRI | y | y | 高优先级带数据可读 |
POLLOUT | y | y | 普通数据可写 |
POLLWRNORM | y | y | 普通数据可写 |
POLLWRBAND | y | y | 优先级带数据可写 |
POLLERR | n | y | 发生错误 |
POLLHUP | n | y | 发生挂起 |
POLLNVAL | n | y | 描述符不是一个打开的文件 |
poll的就绪条件:
- 所有正规TCP数据和所有UDP数据视为普通数据
- TCP带外数据视为优先级带数据
- 当TCP读半关闭时(收到对端传来的FIN),也视为普通数据,随后的读操作将返回0
-
TCP连接存在错误既可以视为普通数据,也可以视为错误(
POLLERR
)。随后的读操作将返回-1,并设置全局的errno
变量。 - 监听套接字上有新的连接既可以视为普通数据,也可以视为优先级数据。
-
非阻塞式的
connect
的完成视为使对应的套接字可写。
总结
select
和 poll
都支持IO复用,其思路都是调用函数监听多个描述符,当有描述符就绪或者超时的时候函数调用就会返回,对应的描述符集合状态也会改变,这时候再遍历描述符集合,处理其中就绪的部分即可。
这种方式在需要监听的描述符比较小,或者是每次就绪的描述符很多的情况下比较有效;但当描述符很多而且每次只有少数描述符就绪时,效率就比较低了。后面出现的 epoll
就避免了这种线性遍历的问题。
另外 select
还受 FD_SETSIZE
的限制,只能处理较少的描述符,而 poll
则没有这个限制。 poll
监听的集合大小只受进程能打开的文件数量( RLIMIT_NOFILE
)的限制。
以上所述就是小编给大家介绍的《《UNIX网络编程》笔记 - select和poll》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Ant Colony Optimization
Marco Dorigo、Thomas Stützle / A Bradford Book / 2004-6-4 / USD 45.00
The complex social behaviors of ants have been much studied by science, and computer scientists are now finding that these behavior patterns can provide models for solving difficult combinatorial opti......一起来看看 《Ant Colony Optimization》 这本书的介绍吧!