简单分析一下linux下select和poll的使用,加深下自己的记忆,如有不足或错误之处,还请各位道友指导!
在linux中,select,poll和最新的epoll都是IO复用的机制,这里就单说一下select和poll
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
这是select函数的声明:
- int nfds: 所有描述符的总共之数(大小限制为FD_SETSIZE, linux的FD_SETSIZE通常为1024)
- fd_set *readfds:读监听字描述符集合(集合中的套接字若至少有一个准备好读,select便返回)
- fd_set *writefds:写监听字描述符集合(集合中的套接字若至少有一个准备好写,select便返回)
- fd_set *exceptfds:发生异常的描述符集合(集合中套接字若至少有一个发生异常,select便返回)
- struct timeval *timeout:select等待时间
- 注册套接字到相关的集合(使用FD_SET)
- select()轮循检测是否有套接字就绪
- 循环所有的注册的套接字检查是否是select()返回中的就绪套接字(使用FD_ISSET)
(select要注意的是,每次返回后,将所有集合的套接字均清零)
从上面可以看出select的不足:- 检测一个就绪套接字,你需要给所有的套接字FD_ISSET(),若套接字少还行,一旦多了,那就是直接拖速度啊
- 能够监听的套接字数目有限制,一千多个的套接字对于大一点的网络服务器就是‘呵呵‘了
其实还有缺点并不能直接看出来,不过还是要列出来
3. 每次调用select,系统要把套接字集合复制到内核空间
不过优点还是有的:
- 在套接字较少的情况下,效率还是挺高的
- 能够操作纳米级别的时间(比如说你设置个纳秒级别的超时之类的)
- 最后一个也算的话,那就算是他的资历吧,毕竟80年代就出道,人家有时候在一些特殊的系统上也支持
好了,select就说到这了,既然select有着这些限制,然后poll()出来了
int poll(struct pollfd *fds, nfds_t nfds, int timeout)
其中:
struct pollfd
{
int fd;
short events;
short revents;
}
- struct pollfd *fds:结构数组指针,结构包含了描述符fd, 关注的事件events(POLLIN, POLLOUT, POLLERR等), 发生的事件revent;
- nfds_t nfds:结构数据的个数
- int timeout:超时时间
使用步骤基本是:
- 设置pollfd结构
- poll轮循检测就绪套接字
- 循环所有的结构的revent检查是否发生事件
然而对比与select(), poll摆脱了FD_SETSIZE大小的限制,但是它又降低了控制时间timeout的级别(只能到毫秒级),其他的基本一样(比如一样要轮循所有的套机字来找出就绪的套接字,一样要拷贝fd集合到内核空间等)
故,两者的优缺点差不多(毕竟是同一时期的老前辈),就分析到这了。而最新的epoll机制相比于他们,有着很大的改进,这个下次说说。