소켓 쌍의 반대쪽 끝이 닫힐 때 어떻게 알림을 받나요?

소켓 쌍의 반대쪽 끝이 닫힐 때 어떻게 알림을 받나요?

Unix 도메인 소켓(IPC 소켓이라고도 함)을 통해 하위 프로세스(서버)와 통신하는 상위 프로세스(클라이언트)가 있습니다.

소켓은 socketpair()데이터그램 유형을 사용하여 생성됩니다.

나는 posix_spawn()하위 프로세스를 시작하고 close()상위-하위 프로세스에서 필요하지 않은 소켓 쌍의 끝을 시작하는 데 사용합니다.

아이들과 함께 사용 poll()하고 recv().

이것은 모두 좋습니다.

이제 클라이언트가 소켓 끝을 닫거나 클라이언트가 종료될 때 하위(서버)에 알림이 전달되기를 원합니다.

에서 POLLHUP또는 POLLERR이벤트를 받기를 바랐 close()지만 아무 것도 얻지 못했습니다.

열려 있는 2개의 프로세스를 나열하는 Unix 도메인 소켓을 사용할 때 lsof -U소켓의 다른 쪽 끝은 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초였습니다). 이벤트에 대한 클라이언트 프로세스를 종료할 수 있습니다.

관련 정보