面试题答案
一键面试- 基本步骤
- 设置文件描述符为非阻塞模式:通过
fcntl
函数修改文件描述符的标志。 - 使用
select
或epoll
等多路复用机制:select
相对简单,epoll
在处理大量文件描述符时性能更优。 - 设置超时时间:使用
struct timeval
结构体来定义超时时间。 - 执行I/O操作:在多路复用机制返回有数据可读时,进行读取操作。
- 设置文件描述符为非阻塞模式:通过
- 关键函数
fcntl
函数:用于设置文件描述符为非阻塞模式。例如:
int flags = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
- **`select`函数**:多路复用函数,用于监听文件描述符集合的状态变化。
#include <sys/select.h>
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
nfds
是需要检查的文件描述符总数(通常为最大文件描述符值加1)。readfds
、writefds
和exceptfds
分别是读、写和异常事件的文件描述符集合。timeout
为超时时间,如果设置为NULL
则一直阻塞直到有事件发生。struct timeval
结构体定义如下:
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
};
例如设置5秒超时:
struct timeval timeout;
timeout.tv_sec = 5;
timeout.tv_usec = 0;
- **`epoll`相关函数(以`epoll`为例简述)**:
- **`epoll_create`函数**:创建一个`epoll`实例。
#include <sys/epoll.h>
int epoll_create(int size);
size
参数已被忽略,但必须大于0。
- epoll_ctl
函数:控制epoll
实例中所监控的文件描述符。
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
epfd
是epoll_create
返回的epoll
实例文件描述符,op
表示操作类型(如EPOLL_CTL_ADD
、EPOLL_CTL_MOD
、EPOLL_CTL_DEL
),fd
是要操作的文件描述符,event
指定事件类型和关联数据。
- epoll_wait
函数:等待所监控的文件描述符上有事件发生。
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
epfd
为epoll
实例文件描述符,events
用于存储发生事件的文件描述符和事件信息,maxevents
是events
数组的大小,timeout
为超时时间(单位毫秒,-1
表示一直阻塞,0
表示立即返回)。
3. 示例代码(以select
为例)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/select.h>
#include <string.h>
#define BUFFER_SIZE 1024
int main() {
int fd = STDIN_FILENO; // 假设从标准输入读取,实际应用中可能是套接字等文件描述符
int flags = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
fd_set read_fds;
FD_ZERO(&read_fds);
FD_SET(fd, &read_fds);
struct timeval timeout;
timeout.tv_sec = 5;
timeout.tv_usec = 0;
int activity = select(fd + 1, &read_fds, NULL, NULL, &timeout);
if (activity < 0) {
perror("select error");
exit(EXIT_FAILURE);
} else if (activity == 0) {
printf("Timeout occurred\n");
} else {
char buffer[BUFFER_SIZE];
ssize_t bytes_read = read(fd, buffer, sizeof(buffer));
if (bytes_read < 0) {
perror("read error");
exit(EXIT_FAILURE);
}
buffer[bytes_read] = '\0';
printf("Read data: %s\n", buffer);
}
return 0;
}
此代码先将标准输入设置为非阻塞模式,然后使用select
函数设置5秒超时等待输入。如果超时则输出提示信息,如果有数据可读则读取并输出。实际应用中套接字等文件描述符的处理类似,但需根据具体协议进行操作。