一、 select 函数 概述
0、 select 其实是 linux I/O模型中的-------- I/O 复用 模型。
可实现统一进程 处理 多个客户端的连接。
1、原型:int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
nfds: maxFd + 1 注意: 是fd的最大值 + 1, 不是最大个数+1;
readfds、writefds、exceptfds 分别是 读、写、错误 事件的 fd 集合;
timeout :select 阻塞等待的时间,NULL 表示 无事件时 select 阻塞;timeout里边的值为0,则表示 select不阻塞。
2、返回值
正数: 监听到的 fd 事件的 个数;
0 : 超时 无事件;
负数: select 错误, 存在errno中;
3、简单举例
serverfd = socket()
setsockopt SO_REUSEADDR
bind();
listen;
while(1)
{
FD_ZERO() //清空文件描述符集
FD_SET(serverfd, &readfd_set); //服务器socket加入到监听中
for()
if allfd[i] > 0 FD_SET(allfd[i], &readfd_set) ;
ret = select(maxfd+1, &readfd_set, NULL, NULL, &timeout); // 注意,经过select操作,readset的
// 值 已经改变,变成了该fd有事件该位才是1。
if ret == 0 continue;
if ret < 0
{
if errno == EINTR continue; //阻塞 过程中 被 信号 打断
else
break;
}
if FD_ISSET(serverfd, &readfd_set) // 处理 accept 事件
{
newfd = accept();
allfd[i++] = newfd;
}
for()
if FD_ISSET(allfd[i], &readfd_set) // 处理 read 或者 write 事件
{
n = read();
}
//若close(somefd), 则 记得 把somefd从 allfd[i] 中 删除
}
void FD_CLR(int fd, fd_set *set); // set中清除指定 fd
int FD_ISSET(int fd, fd_set *set); // 判断 fd 是否在 set集里, 即检测 该 fd 是否有事件发生
void FD_SET(int fd, fd_set *set); // 把fd 加入到 set 集里
void FD_ZERO(fd_set *set); //清空 set集合
1、深入一点 了解 fd_set;
2、其实 就是 一个 unlong 的数组, 即一个大的 bitmap;
3、FD_SET(2, &set) 相当于 把 set 这个大的 bitmap的 第二位 置为1;
4、所以,fd的个数及 最大值, 就受该数组大bitmap 位数限制, 8*8*16(8字节*8bits*16个数组元素);
5、所以fd的最大值为 1024, 当然,最大个数 也就 限制在1024个了;
6、经select 处理后 , set就 存储的 有事件的fd的 bitmap, 即有事件了对应的set中的bitmap那一位就为1;
7、FD_ISSET(fd, &set) 就是1<<fd 后与 set的bitmap 相与, 为1 表示bitmap该位 为1, 即该fd有事件;
五、