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
?
この例と説明する例の2番目の小さな違いは、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秒でした)。イベントのクライアントプロセスを終了できます。