MST

星途 面试题库

面试题:网络编程中select函数的基本使用

请简述在网络编程中select函数的参数构成及其含义,并给出一个简单的使用select函数监听多个套接字的示例代码框架,包括初始化套接字、设置select相关参数等步骤。
30.8万 热度难度
后端开发网络编程

知识考点

AI 面试

面试题答案

一键面试

select函数参数构成及其含义

int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

  • nfds:监控的文件描述符集里最大文件描述符加1。
  • readfds:指向fd_set结构的指针,用于检查可读性的文件描述符集合。
  • writefds:指向fd_set结构的指针,用于检查可写性的文件描述符集合。
  • exceptfds:指向fd_set结构的指针,用于检查是否有异常条件待处理的文件描述符集合。
  • timeout:指向struct timeval结构的指针,用于设置select函数的超时时间。如果为NULL,表示select函数将一直阻塞,直到有事件发生;如果timeval结构体中的tv_sectv_usec都为0,则select函数不阻塞,立即返回。

示例代码框架

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>

#define PORT 8080
#define MAX_CLIENTS 10

int main(int argc, char const *argv[]) {
    int server_fd, new_socket, valread;
    struct sockaddr_in address;
    int opt = 1;
    int addrlen = sizeof(address);
    char buffer[1024] = {0};

    // 创建套接字
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    // 设置套接字选项
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }

    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(PORT);

    // 绑定套接字
    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }

    // 监听套接字
    if (listen(server_fd, MAX_CLIENTS) < 0) {
        perror("listen");
        exit(EXIT_FAILURE);
    }

    fd_set read_fds;
    fd_set tmp_fds;
    FD_ZERO(&read_fds);
    FD_ZERO(&tmp_fds);

    // 将服务器套接字添加到读集合中
    FD_SET(server_fd, &read_fds);
    int activity, max_sd;
    max_sd = server_fd;

    while (1) {
        tmp_fds = read_fds;
        activity = select(max_sd + 1, &tmp_fds, NULL, NULL, NULL);

        if (activity < 0) {
            perror("select error");
        } else if (activity > 0) {
            if (FD_ISSET(server_fd, &tmp_fds)) {
                if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
                    perror("accept");
                    continue;
                }
                FD_SET(new_socket, &read_fds);
                if (new_socket > max_sd) {
                    max_sd = new_socket;
                }
            }
            for (int i = 0; i <= max_sd; i++) {
                if (FD_ISSET(i, &tmp_fds)) {
                    valread = read(i, buffer, 1024);
                    if (valread == 0) {
                        close(i);
                        FD_CLR(i, &read_fds);
                    } else {
                        buffer[valread] = '\0';
                        printf("Message received: %s\n", buffer);
                    }
                }
            }
        }
    }
    close(server_fd);
    return 0;
}