You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言多线程Socket调用accept()时出现Bad file descriptor错误

自定义HTTP服务器accept()报错:bad file descriptor

需求

重写网站上使用的旧版遗留自定义HTTP服务器。

问题现象

调用accept()函数时,终端输出Can't accept client: bad file descriptor错误,代码表面无明显问题。

已尝试的解决方法

  • 调整代码执行顺序
  • 怀疑自有模板存在隐藏错误,曾复制网上随机模板测试,但因不满意换回自己的代码

相关代码

#include <stdio.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>

// This version of software is licensed under public domain feel free to use for any purpose
typedef struct{
    char* http_path;
    void (*function)();
} location;
unsigned short server_count = 0;

typedef struct{
    unsigned char running;
    unsigned id;
    unsigned locationCount;
    location* locations;
    unsigned port;    
} http_server_t;
http_server_t* servers;

char nServer(unsigned short port) {
    server_count++;
    char status = server_count;
    // The warning happens here can be disregarded
    if(server_count == 1) {
        status = (servers = malloc(sizeof(http_server_t)*server_count)) != NULL;
    }else{
        status = (servers = realloc(servers, sizeof(http_server_t)*server_count)) != NULL;
    }
    if(!status){
        return -1;
    }
    servers[server_count-1].port = port;
    servers[server_count-1].running = 1;
    servers[server_count-1].locationCount = 0;
    servers[server_count-1].locations = NULL;
    return server_count;
}

typedef struct __attribute__((packed)) {
    unsigned sock;
    struct sockaddr_in inf;
} serverHandlerData;

void serveClient() {

}

void* socketHandle(void* data) {
    serverHandlerData *fixed = data;
    unsigned sock = fixed->sock;
    struct sockaddr_in in = fixed->inf;
    free(data); // 释放动态分配的参数内存

    if(bind(sock, (struct sockaddr *)&in, sizeof(struct sockaddr))) {
        perror("Can't bind");
        close(sock);
        return NULL;
    } 

    if((listen(sock, 5)) < 0) {
        perror("Can't listen the socket");
        close(sock);
        return NULL;
    }        

    for(;;) {
        int csock;
        struct sockaddr_in caddr;
        socklen_t caddr_len = sizeof(caddr);
        if((csock = accept(sock, (struct sockaddr*)&caddr, &caddr_len)) < 0) {
            perror("Can't accept client");
            close(sock);
            return NULL;
        }

        unsigned char* buffer = malloc(101); // 多留一个字节存终止符
        if(buffer) {
            ssize_t read_len = read(csock, buffer, 100);
            if(read_len > 0) {
                buffer[read_len] = '\0'; // 添加字符串终止符
                printf("%s", buffer);
            }
            free(buffer);
        }
        close(csock);
    }
    return NULL;
}

void iServers() {
    for(unsigned long x = 0; x < server_count; x++) {
        struct sockaddr_in addr;
        unsigned int sock = 0;
        if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
            perror("Socket can't be made due a error");
            return;
        }
        printf("Starting server on port %d\n", servers[x].port);

        memset(&addr, 0, sizeof(addr));
        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = htonl(INADDR_ANY);
        addr.sin_port = htons(servers[x].port);
        
        // 动态分配参数,避免局部变量销毁问题
        serverHandlerData* s = malloc(sizeof(serverHandlerData));
        if(!s) {
            perror("Failed to allocate server data");
            close(sock);
            return;
        }
        s->sock = sock;
        s->inf = addr;

        pthread_t serverHandle;
        if(pthread_create(&serverHandle, NULL, socketHandle, s) != 0) {
            perror("Failed to create thread");
            free(s);
            close(sock);
            return;
        }
        pthread_detach(serverHandle); // 分离线程,避免资源泄漏
    }
}

unsigned char running = 1;

void ctrlCHandler(int sig){
    running = 0;
}

int main() {
    signal(SIGINT, ctrlCHandler);
    if(nServer(4080) == -1) {
        perror("Failed to create server 1");
        return 1;
    }
    if(nServer(1010) == -1) {
        perror("Failed to create server 2");
        return 1;
    }

    iServers();
    
    // 保持主线程运行,等待信号
    while(running) {
        sleep(1);
    }
    
    // 清理服务器资源
    for(unsigned long x = 0; x < server_count; x++) {
        free(servers[x].locations);
    }
    free(servers);
    return 0;
}

问题根源与修复说明

  1. accept()参数错误:原代码中accept(csock, ...)使用了未初始化的csock作为监听套接字参数,正确应该传入之前创建的sock(即fixed->sock),同时第三个参数需要传入socklen_t类型的指针,而非直接传值。
  2. 内存分配与数组索引错误:nServer中malloc(sizeof(servers)*server_count)错误使用指针大小计算内存,应改为sizeof(http_server_t);数组索引从0开始,servers[server_count]越界,需改为servers[server_count-1]。
  3. 线程传参非法:原代码传递局部变量s的地址给线程,线程启动时局部变量已销毁,改为动态分配serverHandlerData内存,在线程内释放。
  4. 服务器遍历循环错误:原循环x=1; x<server_count会漏掉第一个服务器,改为x=0; x<server_count遍历所有服务器。
  5. listen()参数不合法:listen(sock, 0)的backlog参数不符合POSIX标准,改为合理值5。
  6. 不安全的printf调用:原printf(buffer)可能因缓冲区无终止符或包含格式化字符导致错误,改为printf("%s", buffer)并确保缓冲区以'\0'结尾。
  7. 资源泄漏问题:添加线程分离pthread_detach,主线程等待信号后清理服务器资源,避免内存泄漏。

内容的提问来源于stack exchange,提问作者drk1

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 19:36:29