MST

星途 面试题库

面试题:C语言在复杂Linux网络场景下的资源管理与故障处理

在一个基于C语言开发的大型Linux网络应用中,涉及多个网络连接、多种网络协议(如TCP、UDP)以及大量动态内存分配。描述如何有效地进行资源管理(包括文件描述符、内存等)以避免资源泄漏,同时说明当网络出现故障(如连接中断、丢包等)时,如何设计健壮的故障处理机制来保证系统的稳定性和可靠性,给出关键设计思路和核心代码片段。
29.6万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试

资源管理

  1. 文件描述符管理
    • 打开文件描述符时记录:在打开网络套接字(如socket()函数调用)时,将返回的文件描述符记录在一个数组或链表中。
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        perror("socket creation failed");
        exit(EXIT_FAILURE);
    }
    // 假设fd_list是一个数组,fd_count是已使用的文件描述符数量
    fd_list[fd_count++] = sockfd;
    
    • 关闭文件描述符:在程序结束或不再需要某个连接时,遍历记录文件描述符的数组或链表,关闭每个文件描述符。
    for (int i = 0; i < fd_count; i++) {
        close(fd_list[i]);
    }
    
  2. 动态内存管理
    • 使用内存池:预先分配一块较大的内存,根据需要从这块内存中分配小块内存。当不再使用时,将小块内存归还到内存池,而不是直接释放给系统。
    • 记录分配的内存:使用链表记录每次动态分配的内存地址。在释放内存时,遍历链表释放所有分配的内存。
    void *ptr = malloc(size);
    if (ptr == NULL) {
        perror("malloc failed");
        exit(EXIT_FAILURE);
    }
    // 假设mem_list是一个链表,将ptr添加到链表中
    add_to_mem_list(ptr);
    
    • 释放内存:在程序结束或不再需要内存时,遍历链表释放所有内存。
    free_memory_list(mem_list);
    

故障处理机制

  1. 连接中断处理
    • 心跳机制:在TCP连接中,定期发送心跳包(如简单的字节流)给对方。如果在一定时间内没有收到心跳响应,认为连接中断。
    // 发送心跳包
    int send_heartbeat(int sockfd) {
        char heartbeat_msg[] = "HEARTBEAT";
        ssize_t bytes_sent = send(sockfd, heartbeat_msg, sizeof(heartbeat_msg), 0);
        if (bytes_sent < 0) {
            perror("send heartbeat failed");
            return -1;
        }
        return 0;
    }
    
    • 重新连接:当检测到连接中断时,尝试重新建立连接。
    int reconnect(int sockfd, struct sockaddr_in servaddr) {
        close(sockfd);
        sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (sockfd < 0) {
            perror("socket creation failed");
            return -1;
        }
        if (connect(sockfd, (const struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
            perror("connect failed");
            close(sockfd);
            return -1;
        }
        return sockfd;
    }
    
  2. 丢包处理
    • 确认机制:对于TCP,本身有确认机制。对于UDP,可以自己实现确认机制。发送数据时记录发送的数据包,接收方返回确认消息。如果在一定时间内没有收到确认消息,重发数据包。
    // UDP发送数据并等待确认
    int send_udp_data(int sockfd, struct sockaddr_in servaddr, const char *data, size_t len) {
        ssize_t bytes_sent = sendto(sockfd, data, len, MSG_CONFIRM, (const struct sockaddr *)&servaddr, sizeof(servaddr));
        if (bytes_sent < 0) {
            perror("sendto failed");
            return -1;
        }
        // 等待确认
        char ack[ACK_SIZE];
        struct sockaddr_in from;
        socklen_t fromlen = sizeof(from);
        fd_set read_fds;
        FD_ZERO(&read_fds);
        FD_SET(sockfd, &read_fds);
        struct timeval timeout;
        timeout.tv_sec = 1; // 等待1秒
        timeout.tv_usec = 0;
        int activity = select(sockfd + 1, &read_fds, NULL, NULL, &timeout);
        if (activity < 0) {
            perror("select error");
            return -1;
        } else if (activity > 0) {
            ssize_t bytes_recv = recvfrom(sockfd, ack, ACK_SIZE, MSG_WAITALL, (struct sockaddr *)&from, &fromlen);
            if (bytes_recv < 0) {
                perror("recvfrom failed");
                return -1;
            }
            // 检查确认消息
            if (check_ack(ack)) {
                return 0;
            }
        }
        // 重发
        return send_udp_data(sockfd, servaddr, data, len);
    }