libevent库源码学习-poll/select( linux)
来源:互联网 发布:淘宝买汽枪怎么搜索 编辑:程序博客网 时间:2024/05/16 07:14
这两种实际上差不多,都是把一组fd传送给kernal,然后返回一个就绪fd的数量,然后开始遍历所有的fd,找到那些可读或者可写的。
区别在于,poll相比select来说,传送给kernal的数组要小,这可能是它唯一的优势,其他方面区别不大....
api
1 int select(int fdsp1, fd_set *readfds, fd_set *writefds, fd_set *errorfds, const struct timeval *timeout);
各个参数含义如下:
- int fdsp1:最大描述符值 + 1
- fd_set *readfds:对可读感兴趣的描述符集
- fd_set *writefds:对可写感兴趣的描述符集
- fd_set *errorfds:对出错感兴趣的描述符集
- struct timeval *timeout:超时时间(注意:对于linux系统,此参数没有const限制,每次select调用完毕timeout的值都被修改为剩余时间,而unix系统则不会改变timeout值)
- readfds集合中有描述符可读
- writefds集合中有描述符可写
- errorfds集合中有描述符遇到错误条件
- 指定的超时时间timeout到了
select函数返回状态发生变化的描述符总数。返回0意味着超时。失败则返回-1并设置errno。可能出现的错误有:EBADF(无效描述符)、EINTR(因终端而返回)、EINVAL(nfds或timeout取值错误)。
设置描述符集合通常用如下几个宏定义:
1 FD_ZERO(fd_set *fdset); /* clear all bits in fdset */
2 FD_SET(int fd, fd_set *fdset); /* turn on the bit for fd in fd_set */
3 FD_CLR(int fd, fd_set *fdset); /* turn off the bit for fd in fd_set */
4 int FD_ISSET(int fd, fd_set *fdset); /* is the bit for fd on in fdset? */
2 FD_SET(int fd, fd_set *fdset); /* turn on the bit for fd in fd_set */
3 FD_CLR(int fd, fd_set *fdset); /* turn off the bit for fd in fd_set */
4 int FD_ISSET(int fd, fd_set *fdset); /* is the bit for fd on in fdset? */
如:
1 fd_set rset;
2 FD_ZERO(&rset); /* initialize the set: all bits off */
3 FD_SET(1, &rset); /* turn on bit for fd 1 */
4 FD_SET(4, &rset); /* turn on bit for fd 4 */
5 FD_SET(5, &rset); /* turn on bit for fd 5 */
2 FD_ZERO(&rset); /* initialize the set: all bits off */
3 FD_SET(1, &rset); /* turn on bit for fd 1 */
4 FD_SET(4, &rset); /* turn on bit for fd 4 */
5 FD_SET(5, &rset); /* turn on bit for fd 5 */
当select返回的时候,rset位都将被置0,除了那些有变化的fd位。
当发生如下情况时认为是可读的:
- socket的receive buffer中的字节数大于socket的receive buffer的low-water mark属性值。(low-water mark值类似于分水岭,当receive buffer中的字节数小于low-water mark值的时候,认为socket还不可读,只有当receive buffer中的字节数达到一定量的时候才认为socket可读)
- 连接半关闭(读关闭,即收到对端发来的FIN包)
- 发生变化的描述符是被动套接字,而连接的三路握手完成的数量大于0,即有新的TCP连接建立
- 描述符发生错误,如果调用read系统调用读套接字的话会返回-1。
- socket的send buffer中的字节数大于socket的send buffer的low-water mark属性值以及socket已经连接或者不需要连接(如UDP)。
- 写半连接关闭,调用write函数将产生SIGPIPE
- 描述符发生错误,如果调用write系统调用写套接字的话会返回-1。
select默认能处理的描述符数量是有上限的,为FD_SETSIZE的大小。
对于timeout参数,如果置为NULL,则表示wait forever;若timeout->tv_sec = timeout->tv_usec = 0,则表示do not wait at all;否则指定等待时间。
如果使用select处理多个套接字,那么需要使用一个数组(也可以是其他结构)来记录各个描述符的状态。而使用poll则不需要,下面看poll函数。
2 int poll(struct pollfd *fdarray, unsigned long nfds, int timeout);
各参数含义如下:
- struct pollfd *fdarray:一个结构体,用来保存各个描述符的相关状态。
- unsigned long nfds:fdarray数组的大小,即里面包含有效成员的数量。
- int timeout:设定的超时时间。(以毫秒为单位)
- -1:有错误产生
- 0:超时时间到,而且没有描述符有状态变化
- >0:有状态变化的描述符个数
pollfd的结构如下:
1 struct pollfd {
2 int fd; /* descriptor to check */
3 short events; /* events of interest on fd */
4 short revents; /* events that occured on fd */
5 };
2 int fd; /* descriptor to check */
3 short events; /* events of interest on fd */
4 short revents; /* events that occured on fd */
5 };
其实poll()和select()函数要处理的问题是相同的,只不过是不同组织在几乎相同时刻同时推出的,因此才同时保留了下来。select()函数把可读描述符、可写描述符、错误描述符分在了三个集合里,这三个集合都是用bit位来标记一个描述符,一旦有若干个描述符状态发生变化,那么它将被置位,而其他没有发生变化的描述符的bit位将被clear,也就是说select()的readset、writeset、errorset是一个value-result类型,通过它们传值,而也通过它们返回结果。这样的一个坏处是每次重新select 的时候对集合必须重新赋值。而poll()函数则与select()采用的方式不同,它通过一个结构数组保存各个描述符的状态,每个结构体第一项fd代表描述符,第二项代表要监听的事件,也就是感兴趣的事件,而第三项代表poll()返回时描述符的返回状态。合法状态如下:
- POLLIN: 有普通数据或者优先数据可读
- POLLRDNORM: 有普通数据可读
- POLLRDBAND: 有优先数据可读
- POLLPRI: 有紧急数据可读
- POLLOUT: 有普通数据可写
- POLLWRNORM: 有普通数据可写
- POLLWRBAND: 有紧急数据可写
- POLLERR: 有错误发生
- POLLHUP: 有描述符挂起事件发生
- POLLNVAL: 描述符非法
对于POLLIN | POLLPRI等价与select()的可读事件;POLLOUT | POLLWRBAND等价与select()的可写事件;POLLIN 等价与POLLRDNORM | POLLRDBAND,而POLLOUT等价于POLLWRBAND。如果你对一个描述符的可读事件和可写事件以及错误等事件均感兴趣那么你应该都进行相应的设置。
对于timeout的设置如下:
- INFTIM: wait forever
- 0: return immediately, do not block
- >0: wait specified number of milliseconds
使用的方式也都差不多,返回后,都要遍历一遍数组,从而确定那个fd是就绪的
- libevent库源码学习-poll/select( linux)
- libevent库源码学习-poll/select( linux) .devpoll(/dev/poll)( linux) ,epoll(linux)
- libevent库源码学习-devpoll(/dev/poll)( linux)
- libevent库源码学习-epoll( linux)
- Linux学习:多路复用 select / poll
- linux 驱动学习之poll与select
- 关于Libevent的快速可移植非阻塞网络编程(block-》select-》poll-》epoll-》libevent)
- select\poll源码
- libevent源码学习研究(libevent-0.1)
- libevent库源码学习-kqueue( freebsd)
- Linux socket模型(select, poll, epoll)
- select和poll服务器实现(Linux)
- linux select poll
- linux select&poll
- linux之select/poll
- linux select poll epoll
- linux epoll poll select
- 驱动程序学习(五)select and poll
- 存储引擎
- 以前学C的记录
- 【编译原理】第二章 一个简单的语法制导翻译器
- 使用迭代器 遍历文件的信息
- JSONObject.fromObject 转换JSON字符串Map的问题
- libevent库源码学习-poll/select( linux)
- Java 并发的初步学习 (Thread的 Runnable Callable 试用)
- 计算机网络Tanenbaum(第四版)笔记
- 建造者模式
- C#问题
- struts2下载文件时严重: Can not find a java.io.InputStream with the name [targetFile] in the invocation
- JAVA 数字图像处理----非白即黑的灰,2B青年的自画像
- C++中的Big Three
- 绑定cpu