Appearance
Select
select 是一种基于IO多路复用的机制,它可以同时监视多个文件描述符,一旦某个文件描述符就绪,就会通知应用程序进行相应的读写操作。下面是 select 的 IO 多路复用原理:
- 应用程序调用 select 函数,将需要监视的文件描述符集合传递给内核。
- 内核将这些文件描述符加入到一个等待队列中,并将进程阻塞,等待文件描述符就绪。
- 当一个或多个文件描述符就绪时,内核将这些文件描述符从等待队列中移除,并将它们加入到一个准备就绪队列中。
- select 函数返回时,应用程序可以通过遍历准备就绪队列来确定哪些文件描述符已经就绪,然后进行相应的读写操作。
- 应用程序可以再次调用 select 函数来监视文件描述符集合的变化。
需要注意的是,select 的缺点是对文件描述符数量有限制,一般情况下是 1024 个,同时每次调用 select 函数都需要将文件描述符集合从用户空间拷贝到内核空间,这会带来一定的开销。因此,在高并发和大规模连接的场景下,select 并不是最优的选择。目前常用的 IO 多路复用机制有 poll、epoll 等。

TCP 服务器模型
c
/* select TCP Server */
std = socket()
bind() listen()
while(1) {
tempfds = readfds /* 备份集合 */
select(maxfd + 1, &tempfds,
NULL, NULL, NULL)
for(i = 0; i <= maxfd; i++) {
if(0 == FD_ISSET(i, &tempfds))
continue /* 集合中无该文件描述符 */
if(0 == i) scanf() /* 标准输入 */
else if (sfd == i) { /* 新的连接 */
newfd = accept()
FD_SET(newfd, &readfds)
maxfd = MAX(maxfd, newfd)
} else { /* 旧的连接 */
res = recv()
if(0 == res) {
close(i) FD_CLR(i, &readfds)
for(j == maxfd; j >= 0; j--)
if(FD_ISSET(j, &readfds))
break
maxfd = j
continue
}
printf("%s\n", buf)
}
}
}
close(fsd)