select:
int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);
nfds: 当前所有集合中最大的描述符值
readfds:探测可读描述符集合
writefds:探测可写描述符集合
exceptfds:探测异常描述符集合
timeout:等待超时时间,0–>非阻塞,NULL–>永久阻塞
void FD_CLR(int fd, fd_set *set);从集合中删除指定描述符
int FD_ISSET(int fd, fd_set *set);判断集合中是否有指定描述符
void FD_SET(int fd, fd_set *set);向集合中添加指定描述符
void FD_ZERO(fd_set *set);清空集合
优点:可移植性较强
缺点:
(1)、监听描述符有上限个数1024(可以修改头文件,但需要重编译内核)
(2)、需要定义数组保存所有描述符值,
以便每次在新连接到来或者有旧连接关闭时,可以重新确定最大的描述符的值
(3)、每次处理完毕后,需要清空并重新向集合中添加描述符
(因为select描述符状态的改变是直接在原有基础上改变的,因此需要每次情况)
(4)、当有就绪描述符时,select并不会告诉我们哪一个描述符已经就绪,
指示在原有集合上修改状态,因此当我们处理的时候,
需要循环便利集合中的所有描述符才能判断哪一个是就绪描述符---
(当监听数目过大时,效率较低)
1、创建socket。
2、定义监听地址信息,并为socket绑定监听地址。
3、开始监听。(告诉系统开始监听地址是否有数据到来)
4、将socket描述符添加到select的监听集合。(监听集合用于select监听到判断集合中的描述符是否就绪)
5、select开始监听
6、seletc返回值
<0 出错
=0 等待超时(指定时间内没有就绪的描述符)
>0 已经有描述符就绪
7、当描述符就绪,判断描述符是否等于监听socket描述符(代表由新的连接请求)
a.=监听socket描述符(accept处理新的连接器请求),确定当前最大描述符的值。
b.!=监听描述符(代表有传输数据到来),接收数据。
c.接受出错,将描述符从select监听集合中删除,并关闭,重新确定最大描述符值。
8、关闭描述符
epoll:
1、创建socket
2、定义监听地址信息,并为socket绑定监听地址
3、开始监听(告诉系统开始监听地址是否有数据到来)
4、创建epoll监听集合
5、定义事件结构,并将事件与描述符关联
6、将描述符与事件添加到epoll监听集合
7、开始epoll监听(返回值判断)
a.<0 epoll_wait错误
b.=0 epoll_wait超时
c.>0 就绪的时间个数,将已经就绪的时间放到一个指定的事件数组中,
8、根据就绪的事件个数,循环遍历就绪事件数组
a.判断事件fd是否=监听描述符
== 处理新连接
!= 其他的数据传输事件
b.传输若出错,则将描述符从epoll监听集合中删除,并关闭
9、关闭