Absorbed__ 2023-11-03 11:29 采纳率: 60%
浏览 6
已结题

父进程无法接收到子进程终止信号

在使用多进程 TCP 通信过程中 , 父进程接收不到子进程退出的信号SIGCHLD,没有调用
recycleChild函数,想知道如何才能让父进程接收到信号。
子进程使用ctrl+c 结束进程时可以接收到SIGINT信号 ,并调用exit(-1) 退出

如图:子进程结束时 父进程没有调用recycleChild 函数处理信号

img

img

Server

#include <stdio.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <errno.h>
#include <signal.h>
#include <wait.h>

#define SERVERIP "127.0.0.1"
#define PORT 6789

void recycleChild(int arg)
{
    //while 是为了处理多个信号
    printf("接收信号\n");
    while (1)
    {
        int ret = waitpid(-1, NULL, WNOHANG);
        if (ret == -1)
        {
            // 所有子进程都回收了
            break;
        }
        else if (ret == 0)
        {
            // 还有子进程活着
            break;
        }
        else
        {
            // 回收子进程
            printf("子进程 %d 被回收了\n", ret);
        }
    }
}

int main()
{
    // 注册信号捕捉
    struct sigaction act;
    act.sa_flags = 0;
    sigemptyset(&act.sa_mask);
    act.sa_handler = recycleChild;
    sigaction(SIGCHLD, &act, NULL);

    // 1. 创建 socket(用于监听的套接字)
    int listenfd = socket(AF_INET, SOCK_STREAM, 0);
    if (listenfd == -1)
    {
        perror("socket");
        exit(-1);
    }

    // 2. 绑定
    struct sockaddr_in server_addr;
    server_addr.sin_family = PF_INET;
    // 点分十进制转换为网络字节序
    inet_pton(AF_INET, SERVERIP, &server_addr.sin_addr.s_addr);
    // 服务端也可以绑定 0.0.0.0 即任意地址
    // server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(PORT);
    int ret = bind(listenfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
    if (ret == -1)
    {
        perror("bind");
        exit(-1);
    }

    // 3. 监听
    ret = listen(listenfd, 8);
    if (ret == -1)
    {
        perror("listen");
        exit(-1);
    }
    // 不断循环等待客户端连接
    while (1)
    {
        // 4. 接收客户端连接
        struct sockaddr_in client_addr;
        socklen_t client_addr_len = sizeof(client_addr);
        int connfd = accept(listenfd, (struct sockaddr *)&client_addr, &client_addr_len);
        if (connfd == -1)
        {
            // 用于处理信号捕捉导致的 accept: Interrupted system call
            if (errno == EINTR)
            {
                continue;
            }
            perror("accept");
            exit(-1);
        }
        pid_t pid = fork();
        if (pid == 0)
        {
            // 子进程
            // 输出客户端信息,IP 组成至少 16 个字符(包含结束符)
            char client_ip[16] = {0};
            inet_ntop(AF_INET, &client_addr.sin_addr.s_addr, client_ip, sizeof(client_ip));
            unsigned short client_port = ntohs(client_addr.sin_port);
            printf("ip:%s, port:%d\n", client_ip, client_port);

            // 5. 开始通信
            // 服务端先接收客户端信息,再向客户端发送数据
            // 接收数据
            char recv_buf[1024] = {0};
            while (1)
            {
                ret = read(connfd, recv_buf, sizeof(recv_buf));
                if (ret == -1)
                {
                    perror("read");
                    exit(-1);
                }
                else if (ret > 0)
                {
                    printf("recv client data : %s\n", recv_buf);
                }
                else
                {
                    // 表示客户端断开连接
                    printf("client closed...\n");
                    // 退出循环,用来解决 出现两次 client closed...
                    break;
                }
                // 发送数据
                char *send_buf = "hello, i am server";
                // 粗心写成 sizeof,那么就会导致遇到空格终止
                write(connfd, send_buf, strlen(send_buf));
            }
            // 关闭文件描述符
            close(connfd);
        }
    }

    close(listenfd);
    return 0;
}


Clinet

#include <stdio.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <errno.h>
#include <signal.h>
#include <wait.h>

#define SERVERIP "127.0.0.1"
#define PORT 6789
void recycleChild(int arg)
{
    printf("子进程exit 退出\n");
    exit(-1);
}
int main()
{
    struct sigaction act;
    act.sa_flags = 0;
    sigemptyset(&act.sa_mask);
    act.sa_handler = recycleChild;
    sigaction(SIGINT, &act, NULL);

    // 1. 创建 socket(用于通信的套接字)
    int connfd = socket(AF_INET, SOCK_STREAM, 0);
    if (connfd == -1)
    {
        perror("socket");
        exit(-1);
    }
    // 2. 连接服务器端
    struct sockaddr_in server_addr;
    server_addr.sin_family = PF_INET;
    inet_pton(AF_INET, SERVERIP, &server_addr.sin_addr.s_addr);
    server_addr.sin_port = htons(PORT);
    int ret = connect(connfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
    if (ret == -1)
    {
        perror("connect");
        exit(-1);
    }

    // 3. 通信
    char recv_buf[1024] = {0};
    while (1)
    {
        // 发送数据
        char *send_buf = "client message";
        // 粗心写成 sizeof,那么就会导致遇到空格终止
        write(connfd, send_buf, strlen(send_buf));
        // 休眠的目的是为了更好的观察,此处使用 sleep 语句会导致 read: Connection reset by peer
        // sleep (1);
        // 接收数据
        ret = read(connfd, recv_buf, sizeof(recv_buf));
        if (ret == -1)
        {
            perror("read");
            exit(-1);
        }
        else if (ret > 0)
        {
            printf("recv server data : %s\n", recv_buf);
        }
        else
        {
            // 表示服务器端断开连接
            printf("client closed...\n");
            break;
        }
        // 休眠的目的是为了更好的观察,放在此处可以解决 read: Connection reset by peer 问题
        sleep(1);
    }
    // 关闭连接
    close(connfd);
    return 0;
}
  • 写回答

2条回答 默认 最新

  • Absorbed__ 2023-11-04 18:20
    关注

    已解决,服务器接收的是自己的子进程退出的信号,所以要观察的是自己,而不是客户端Clinet 。这个点想错了。
    所以只要在关闭文件描述符后使用exit(0) 关闭子进程即可。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

问题事件

  • 系统已结题 11月12日
  • 已采纳回答 11月4日
  • 创建了问题 11月3日

悬赏问题

  • ¥40 微信小程序 使用vant组件ActionSheet 下拉面板,内容区域滚动会触发。scroll-view自定义下拉刷!即使设置停止下拉刷新也不行。
  • ¥15 专业问题提问,7月5号2点之前
  • ¥25 使用cube ai 导入onnx模型时报错
  • ¥15 关于#微信小程序#的问题:用一个网页显示所有关联的微信小程序数据,包括每个小程序的用户访问量
  • ¥15 root的安卓12系统上,如何使apk获得root或者高级别的系统权限?
  • ¥20 关于#matlab#的问题:如果用MATLAB函数delayseq可以对分数延时,但是延时后波形较原波形有幅度上的改变
  • ¥15 使用华为ENSP软件模拟实现该实验拓扑
  • ¥15 通过程序读取主板上报税口的数据
  • ¥15 matlab修改为并行
  • ¥15 尝试访问%1服务的windows注册表时遇到问题。必须先解决此问题,然后才能运行安装过程。(请确认您正在使用管理员权限运行)373