当套接字对的另一端关闭时如何收到通知?

当套接字对的另一端关闭时如何收到通知?

我有一个父进程(客户端)通过 Unix 域套接字(也称为 IPC 套接字)与子进程(服务器)进行通信。

套接字是使用socketpair()数据报类型创建的。

我用来posix_spawn()启动子进程,以及close()父子进程中我不需要的套接字对的末尾。

在孩子身上我使用poll()recv()

这一切都很好。

现在,我希望当客户端关闭套接字末端或客户端终止时通知子级(服务器)。

我本来希望在 上得到一个POLLHUPPOLLERR事件close(),但我什么也没得到。

当使用lsof -U列出我的 2 个进程打开的 Unix 域套接字时,我看到套接字的另一端是none在客户端被杀死之后。

如果这很重要的话,这是在 macOS 上。

我缺少什么?当客户端关闭 Unix 域套接字时如何收到通知?

答案1

我根据您的描述整理了一个示例应用程序,但有一些细微的差别。首先,我使用SOCK_STREAM而不是SOCK_DGRAM.这种变化给了我你正在寻找的行为——POLLHUP意味着套接字不再连接;SOCK_DGRAM不是面向连接的套接字。您有需要使用的理由吗SOCK_DGRAM

此示例与您所描述的第二个小区别是我使用fork()而不是posix_spawn().这不应该影响您感兴趣的行为;对我来说,用 编写独立的示例更容易fork()

#include <poll.h>
#include <stdio.h>
#include <sys/socket.h>
#include <unistd.h>

int main(void)
{
    int sockets[2] = {};

    if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) < 0) {
        perror("socketpair");
        return 1;
    }

    const pid_t pid = fork();
    if (pid < 0) {
        perror("fork");
        return 2;
    }

    if (pid > 0) {
        /* parent */
        close(sockets[0]);
        sockets[0] = 0;

        for (int i = 0; i < 3; ++i) {
            write(sockets[1], "hello", sizeof("hello"));
            sleep(2);
        }

        /* sockets[1] will get closed on parent termination */
        return 0;
    }

    /* child */
    close(sockets[1]);
    sockets[1] = 0;

    struct pollfd fds = {
        .fd = sockets[0],
        .events = POLLIN | POLLHUP,
    };

    while (poll(&fds, 1, 10 * 1000) > 0) {
        if (fds.revents & POLLHUP) {
            printf("--- Received hangup\n");
            break;
        }
        if (fds.revents & POLLERR) {
            printf("!!! Received error\n");
            break;
        }
        if (fds.revents & POLLIN) {
            char buffer[32] = {};

            if (recv(sockets[0], buffer, sizeof buffer, 0) < 0) {
                perror("recv");
                return 3;
            }

            printf("--> Received message '%s'\n", buffer);
        }
    }

    /* sockets[0] will get closed on child termination */
    return 0;
}

在这个程序中,父母给孩子写消息;子进程接收这些消息并处理它们(在这里,只是将它们打印到标准输出)。父进程发送 3 条消息,然后终止。

当我运行这个程序时,我看到了我认为您正在寻找的行为:

$ ./a.out
--> Received message 'hello'
--> Received message 'hello'
--> Received message 'hello'
--- Received hangup

如果您必须使用,SOCK_DGRAM那么对的调用poll()最终将超时(在我的示例中,我有 10 秒的超时)。您可以关闭该事件的客户端进程。

相关内容