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

Ubuntu默认环境下关闭socketpair未触发SIGHUP信号问题排查

问题原因分析与解决

核心原因:SOCK_DGRAM 套接字不会触发 SIGHUP

你使用的是SOCK_DGRAM(UDP数据报)类型的socketpair,UDP属于无连接协议,当父进程关闭对端套接字时,系统不会向子进程发送SIGHUP信号。只有SOCK_STREAM(流式TCP)套接字在对端关闭时,本地read会返回EOF,但即便如此,系统也不会自动发送SIGHUP——SIGHUP的触发场景是终端关闭、进程组组长退出等,和套接字关闭没有直接关联。

子进程残留的根源

子进程中的read调用在UDP套接字上会一直阻塞(因为没有数据可读,且对端关闭不会让read返回),加上后续的sleep,导致子进程进入无限循环,只能手动终止。

信号处理的误解

父进程在fork前注册的SIGHUP处理函数会被子进程继承,但这不是问题关键——关键是根本不会产生SIGHUP信号,所以处理函数自然不会被触发。

修复方案

方案1:改用流式套接字(推荐)

将socketpair的类型改为SOCK_STREAM,此时父进程关闭套接字后,子进程的read会返回-1(表示连接已关闭),可直接检测该状态退出:

// 修改socketpair创建代码
socketpair(AF_LOCAL, SOCK_STREAM, 0, socket);

// 子进程函数修改为
void child(int socket) {
    while (true) {
        char buf[100];
        int n = read(socket, buf, 10);
        if (n <= 0) { // 检测到EOF或错误
            printf("connection closed, exiting\n");
            break;
        }
        printf("n=%d, '%s'\n", n, buf);
        sleep(1);
    }
}

方案2:父进程主动发送SIGHUP

如果必须使用UDP,可以在父进程关闭套接字后,主动给子进程发送SIGHUP信号:

int main() {
    int socket[2];
    socketpair(AF_LOCAL, SOCK_DGRAM, 0, socket);

    signal(SIGHUP, [](int sig) {
        printf("signal received: %d\n", sig);
        exit(0); // 收到信号后退出,避免残留
    });

    pid_t child_pid;
    switch (child_pid = fork()) { // 保存子进程PID
        case 0:
            close(socket[1]);
            child(socket[0]);
            break;

        default:
            close(socket[0]);
            parent(socket[1]);
            kill(child_pid, SIGHUP); // 主动发送SIGHUP
            break;

        case -1:
            return 1;
    }

    return 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 12:47:42