多路 IO 转接 :select 函数

(1)头文件:

#include <sys/select.h>

(2)函数原型:

int select( int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,struct timeval *timeout );

(3)参数说明
1)参数1:监听的所有文件描述符中,最大文件描述符的编号 + 1(即监听 fd 的总个数)。
2)参数2、3、4:监听的文件描述符 “是否可读”、“是否可写”、“是否异常” 的事件;fd_set代表文件描述符集合,本质是位图。
3)参数5:设定超时返回结果,若填 NULL 代表永久阻塞,直至有事件发生, 若值为0代表立即返回,非阻塞效果。
这里有两点要注意的地方:
1)是最常监听 readfds;writefds 在 epoll 反应堆会使用;exceptfds 一般是内核给系统函数内部使用。
2)以参 2 readfds 为例,并不是我监听它可读,它就一定可读,因此在设计上,都是传入传出参数。传入体现在告诉内核,我想监听谁是否可读。传出体现在通过 select 函数的监听,内核告诉我具体结果,谁是可读的。如下图
在这里插入图片描述
(4)返回值:
成功返回所监听的满足条件的文件描述符总数量。
例如:
监听 r:fd1 fd2 fd3
w:fd1 fd3
err:fd1 fd2
满足条件 r:fd1 fd3
w:fd1 ; err:fd2
则返回值为4 (不要在意 fd1 是否有重复,因为他们属于不同事件)。
失败:返回 -1,设置 errno (如果 timeout =0, errno = EAGAIN,代表正常)。
(5)添加监听的文件描述符函数:

void FD_ZERO(fd_set *set); // 将 set 清空 全部置 0 
void FD_SET(int fd, fd_set *set); // 将 fd 添加到 set 中清除(0 变 1) 
void FD_CLR(int fd, fd_set *set); // 将 fd 从 set 中清除 (1 变 0) 
int FD_ISSET(int fd, fd_set *set); // 判断 fd 是否在 set 中(返回 1 表明在)

(6)在返回值中确定哪个文件描述符可读,哪个可写

fd_set readfds; // 定义监听读事件的文件描述符集合
FD_ZERO(&readfds); // 清空
FD_SET(fd1, &readfds); 
FD_SET(fd2, &readfds); 
FD_SET(fd3, &readfds); // 监听 fd1、fd2、fd3 是否可读
select(); //以上面结果为例(不考虑 writefds 和 exceptfds)返回值 = 1,但我不知道是谁 
//判断是否在相应集合中
int ret = FD_ISSET(fd1, & readfds);
// 发现 ret = 1 说明可读,意味着客户端向服务器发送数据,可以通过 fd1 读取数据
int ret = FD_ISSET(fd2 & readfds); // 显然 结果 = 0
int ret = FD_ISSET(fd3, & readfds); // 显然 结果 = 0

(7)select 函数优缺点
优点:一个线程就可以支持多个客户端(多路 IO 都有这个优点),可以跨平台(select 独有)。
缺点:
1)同时监听文件描述符的上限是 1024 个,注意不是因为打开文件的上限是 1024(上限数可以修改),而是因为在 select 底层实现时候,fd_set使用了宏 FD_SETSIZE = 1024。
2)返回值是一个数量,需要循环遍历判断到底谁符合条件,因此高并发少访问的时候,效率低。
3)监听集合和满足监听条件的集合是同一个集合,select 后会改变原监听集合,使其无法再次使用,因此,select 前需要将原监听集合保存。
(8)监听事件分类:
需要监听事件分为 2 类,首先一类是建立连接请求(其实是监听读事件即服务器写给我请求,我来读),另一类是读写事件请求 (这些都是建立连接之后的事)。就是说,最开始需要监听一个读描述符,有结果,意味着有客户端请求连接,此时服务器调用 accept 函数便会立即建立连接(虽然 accept 是阻塞函数,但此时不会有阻塞效果),然后再监听读写。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值