面试题答案
一键面试-
检查文件描述符状态的过程:
- 初始化文件描述符集合:
- 使用
fd_set
类型的变量来表示文件描述符集合。对于可读状态检查,定义一个fd_set read_fds
;对于可写状态检查,定义一个fd_set write_fds
。使用FD_ZERO
宏清空这些集合,然后使用FD_SET
宏将需要监控的文件描述符添加到相应的集合中。
- 使用
- 确定最大文件描述符值:
- 遍历存放文件描述符的数组,找出其中最大的文件描述符值
max_fd
。select
函数需要这个值来确定检查的范围。
- 遍历存放文件描述符的数组,找出其中最大的文件描述符值
- 调用
select
函数:select
函数的原型为int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
。将max_fd + 1
作为nfds
参数,read_fds
和write_fds
作为相应的文件描述符集合参数传入,exceptfds
通常设为NULL
。可以设置timeout
参数来控制select
函数的阻塞时间,如果设为NULL
则表示无限期阻塞,直到有文件描述符状态发生变化。
- 检查返回值并处理:
- 根据
select
函数的返回值来判断文件描述符状态变化情况,并进行相应处理。
- 根据
- 初始化文件描述符集合:
-
关键代码实现:
#include <stdio.h>
#include <stdlib.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#define MAX_FDS 10
int main() {
int fds[MAX_FDS];
// 假设这里已经填充了文件描述符
int num_fds = 5;
int max_fd = 0;
fd_set read_fds, write_fds;
FD_ZERO(&read_fds);
FD_ZERO(&write_fds);
for (int i = 0; i < num_fds; i++) {
FD_SET(fds[i], &read_fds);
FD_SET(fds[i], &write_fds);
if (fds[i] > max_fd) {
max_fd = fds[i];
}
}
struct timeval timeout;
timeout.tv_sec = 5; // 设置5秒超时
timeout.tv_usec = 0;
int ret = select(max_fd + 1, &read_fds, &write_fds, NULL, &timeout);
if (ret < 0) {
perror("select error");
exit(EXIT_FAILURE);
} else if (ret == 0) {
printf("select timeout\n");
} else {
for (int i = 0; i < num_fds; i++) {
if (FD_ISSET(fds[i], &read_fds)) {
printf("File descriptor %d is readable\n");
// 处理可读事件,例如从socket读取数据
}
if (FD_ISSET(fds[i], &write_fds)) {
printf("File descriptor %d is writable\n");
// 处理可写事件,例如向socket写入数据
}
}
}
return 0;
}
select
函数返回值的不同情况及其处理方式:- 返回值小于0:
- 表示发生错误,例如系统调用被中断或者提供了无效的参数。通过
perror
函数打印错误信息,并根据具体情况决定是否终止程序,如上述代码中调用exit(EXIT_FAILURE)
。
- 表示发生错误,例如系统调用被中断或者提供了无效的参数。通过
- 返回值等于0:
- 表示
select
函数超时,在设定的timeout
时间内没有任何文件描述符状态发生变化。可以根据程序逻辑决定是继续等待还是进行其他操作,如上述代码中打印超时信息。
- 表示
- 返回值大于0:
- 表示有文件描述符状态发生变化,这个返回值表示状态发生变化的文件描述符的总数。通过
FD_ISSET
宏来检查每个文件描述符是否在相应的fd_set
集合中,从而确定哪些文件描述符可读、可写,然后进行相应的处理,如上述代码中打印可读、可写信息并处理相应事件。
- 表示有文件描述符状态发生变化,这个返回值表示状态发生变化的文件描述符的总数。通过
- 返回值小于0: