套接字:杀死客户端进程也会杀死服务器进程

问题描述 投票:0回答:2

我正在学习套接字并按照 GeeksForGeeks 教程这里。作为测试,我添加了一个 while 循环来封装客户端和服务器端的数据发送和接收。然后我注意到,如果我终止了客户端进程,服务器进程也会退出。这就是我感到困惑的地方——客户端和服务器都有单独的 PID,那么为什么会发生这种情况呢?看起来客户端应该是唯一被杀死的进程。

我在 这篇文章 上看到诀窍是将服务器 accept() 调用放在 while 循环中。但是,服务器不应该一直卡在自己的 while 循环中,试图在不再活动的套接字上读取和发送数据,而不管客户端在做什么?我的 while 循环中没有条件会在连接关闭时退出。 我想我真正的问题是这里发生了什么样的 IPC 会导致这种行为?

我附上我的代码以供参考。

Server.c

    int server_fd, new_socket, valread;
    struct sockaddr_in address;
    int addrlen = sizeof(address);
    int opt = 1;
    char buffer[1024] = { 0 };
    char *hello = "Hello from server";

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

    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt)) < 0) {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }

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

    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);
    }

    if ((new_socket = accept(server_fd, (struct sockaddr*)&address, (socklen_t*)&addrlen)) < 0) {
            perror("accept");
            exit(EXIT_FAILURE);
    }
    while (1) {
        valread = read(new_socket, buffer, sizeof(buffer));
        printf("%s\n", buffer);

        
        send(new_socket, hello, strlen(hello), 0);

    }


    close(new_socket);
    shutdown(server_fd, SHUT_RDWR);

    return 0;
}

Client.c

    int client_fd, status, valread;
    struct sockaddr_in serv_addr;
    char *hello = "Hello from client";
    char buffer[1024] = { 0 };

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

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);

    if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
        perror("Address not supported");
        exit(EXIT_FAILURE);
    }

    if ((status = connect(client_fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr))) < 0) {
        perror("Connection failed");
    }
    
    while (1) {
        send(client_fd, hello, strlen(hello), 0);
        printf("Hello message sent\n");
        valread = read(client_fd, buffer, sizeof(buffer));
        printf("%s\n", buffer);
    }
    

    close(client_fd);

    return 0;

我尝试输出客户端服务器进程的 pids 以验证它们具有单独的进程 ID。我还查看了客户端和服务器之间的共享资源,但没有发现任何表明进程本身会相互依赖的信息。

c linux sockets client-server
2个回答
0
投票

刚找到答案,在这里。似乎当客户端使用 Ctrl+C 关闭时,服务器将尝试在关闭的连接上调用 send() ,这将向服务器进程发出 SIGPIPE,从而终止它。选项 MSG_NOSIGNAL 可以用作服务器发送调用上的标志,这将防止这种行为。


0
投票

您可以使用以下代码忽略

SIGPIPE

signal (SIGPIPE, SIG_IGN);
© www.soinside.com 2019 - 2024. All rights reserved.