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

C语言多线程Web服务器触发SIGABRT错误求助

问题

我是C语言新手,正在搭建一个简易Web服务器作为入门项目,但在正确返回HTML文件、处理完一个请求后,handleClient函数触发了SIGABRT错误。该错误是在引入Posix线程后出现的,我推测这与多线程和错误的内存处理有关,希望有人能为我指引排查方向,或是指出代码中可能存在的问题。

代码实现

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

void serveFile(int socket, const char* filename) {
    char buffer[1024];
    int fd;
    int readBytes;

    fd = open(filename, O_RDONLY);

    if (fd == -1) {
        perror("File open failed");
        return;
    }

    while ((readBytes = read(fd, buffer, sizeof(buffer))) > 0) {
        write(socket, buffer, readBytes);
    }

    close(fd);
}

void *handleClient(void *arg) {
    int socket = *(int*)arg;
    char buffer[1024];
    int readBytes;

    readBytes = read(socket, buffer, sizeof(buffer));

    buffer[readBytes] = '\0';
    printf("Received: %s\n", buffer);

    char *header = "HTTP/1.1 200 OK\nContent-Type: text/html\n\n";
    write(socket, header, strlen(header));

    serveFile(socket, "./helloworld.html");

    close(socket);

    free(arg);

    return NULL;
}

int main() {
    int server_fd, new_socket;
    struct sockaddr_in address;
    int opt = 1;
    int addrlen = sizeof(address);

    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

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

    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address))<0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }

    if (listen(server_fd, 3) < 0) {
        perror("listen");
        exit(EXIT_FAILURE);
    }

    while(1) {
        printf("Waiting for connections...\n");

        int *client_fd = malloc(sizeof(int));

        if ((*client_fd = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen))<0) {
            perror("accept");
            continue;
        }
        
        pthread_t thread_id;

        if(pthread_create(&thread_id, NULL, handleClient, (void *)client_fd)) {
            perror("Could not create thread");
            continue;
        }

        pthread_detach(thread_id);        
    }

    return 0;
}

补充信息

  • 服务器收到的客户端请求:
Received: GET / HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Cache-Control: max-age=0
sec-ch-ua: "Google Chrome";v="123", "Not:A-Brand";v="8", "Chromium";v="123"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "macOS"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br, zstd
Accept-Language: en-US,en;q=0.9,sv-SE;q=0.8,sv;q=0.7
Cookie: access_token="token"
  • 运行环境:搭载M3芯片的macOS系统,使用最新版Chrome测试
  • 错误信息:zsh: abort ./http_server
排查与修复方案

1. 核心崩溃原因:数组越界访问

handleClient中直接使用read的返回值作为数组下标,但**read可能返回-1(读取失败)**,此时buffer[readBytes] = '\0'会变成buffer[-1] = '\0',触发内存访问错误,直接导致SIGABRT。

修复代码:

readBytes = read(socket, buffer, sizeof(buffer) - 1); // 预留1字节存终止符
if (readBytes == -1) {
    perror("Read failed");
    close(socket);
    free(arg);
    return NULL;
}
buffer[readBytes] = '\0';

2. 内存泄漏问题

main函数中malloc了client_fd,但如果accept调用失败,直接continue会导致这块内存无法释放,长期运行会耗尽系统内存。

修复代码:

int *client_fd = malloc(sizeof(int));
if ((*client_fd = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen))<0) {
    perror("accept");
    free(client_fd); // 释放已分配的内存
    continue;
}

3. 线程安全优化(可选)

多线程同时调用printf会导致输出混乱,虽然不会触发崩溃,但可以用互斥锁保证输出有序:

// 在全局区域定义互斥锁
pthread_mutex_t print_mutex = PTHREAD_MUTEX_INITIALIZER;

// 在handleClient的printf前后加锁解锁
pthread_mutex_lock(&print_mutex);
printf("Received: %s\n", buffer);
pthread_mutex_unlock(&print_mutex);

4. write返回值处理(可选)

write可能因网络问题返回-1或写入不完整,建议添加基础检查避免响应发送不完整:

ssize_t writeBytes = write(socket, header, strlen(header));
if (writeBytes == -1) {
    perror("Write header failed");
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 23:36:00