MST

星途 面试题库

面试题:C语言中Linux文件描述符状态检查与多路复用的结合应用

在一个基于Linux的C语言网络服务器程序中,使用select函数进行多路复用,需要同时监控多个文件描述符(包括socket的文件描述符)的可读、可写状态。假设已经有一个数组存放了这些文件描述符,详细说明检查这些文件描述符状态的过程及关键代码实现,同时解释select函数返回值的不同情况及其处理方式。
13.4万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试
  1. 检查文件描述符状态的过程

    • 初始化文件描述符集合
      • 使用fd_set类型的变量来表示文件描述符集合。对于可读状态检查,定义一个fd_set read_fds;对于可写状态检查,定义一个fd_set write_fds。使用FD_ZERO宏清空这些集合,然后使用FD_SET宏将需要监控的文件描述符添加到相应的集合中。
    • 确定最大文件描述符值
      • 遍历存放文件描述符的数组,找出其中最大的文件描述符值max_fdselect函数需要这个值来确定检查的范围。
    • 调用select函数
      • select函数的原型为int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);。将max_fd + 1作为nfds参数,read_fdswrite_fds作为相应的文件描述符集合参数传入,exceptfds通常设为NULL。可以设置timeout参数来控制select函数的阻塞时间,如果设为NULL则表示无限期阻塞,直到有文件描述符状态发生变化。
    • 检查返回值并处理
      • 根据select函数的返回值来判断文件描述符状态变化情况,并进行相应处理。
  2. 关键代码实现

#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;
}
  1. select函数返回值的不同情况及其处理方式
    • 返回值小于0
      • 表示发生错误,例如系统调用被中断或者提供了无效的参数。通过perror函数打印错误信息,并根据具体情况决定是否终止程序,如上述代码中调用exit(EXIT_FAILURE)
    • 返回值等于0
      • 表示select函数超时,在设定的timeout时间内没有任何文件描述符状态发生变化。可以根据程序逻辑决定是继续等待还是进行其他操作,如上述代码中打印超时信息。
    • 返回值大于0
      • 表示有文件描述符状态发生变化,这个返回值表示状态发生变化的文件描述符的总数。通过FD_ISSET宏来检查每个文件描述符是否在相应的fd_set集合中,从而确定哪些文件描述符可读、可写,然后进行相应的处理,如上述代码中打印可读、可写信息并处理相应事件。