Unix IPC套接字:关闭未读取数据的一端

4

我有一个父进程和一个派生的子进程,它们共享一个Unix域IPC套接字,使用socketpair(AF_UNIX, SOCK_STREAM, 0, sockets)创建。这两个进程都关闭了套接字对的一端,并将另一端保存到sock变量中。之后它们会执行以下操作:

int sock; // Unix-domain socket

void child_main()
{
  printf("I am child\n");      
  sleep(1);      
  close(sock);
}

void parent_main()
{
  printf("I am parent\n");

  write(sock, "hello", 5);

  char buf[100];
  int ret = read(sock, buf, 100); // this read will return ECONNRESET
  if (ret == -1) { 
    perror("read");
    exit(-1);
  }
}

父进程将一些数据写入套接字,而子进程没有读取它。相反,子进程关闭了套接字。现在我的担忧是,父进程中的“read”失败并出现ECONNRESET(对等方重置连接),而我希望它返回“0”,表示流结束。因为套接字的另一端通过调用“close”“优雅地”关闭。
现在,我理解这种行为(关闭套接字而不读取挂起的数据会生成ECONNRESET),但这个在哪里有记录呢? man read 没有提到ECONNRESET,但它提到:
其他错误可能会发生,具体取决于连接到fd的对象 Unix域套接字的man页 只说了:
ECONNRESET:远程套接字意外关闭。
但由于Unix域套接字是本地IPC事务,所以我认为它可以更具体地说明此错误发生的情况。

我的“深入思考”如下:如果规范说例如close只会在套接字没有数据可读时生成流结束标记,那么它如何知道另一个进程不是即将要写入一些数据?这不会创建竞争条件吗?内核如何知道连接是否会优雅地关闭?


不太确定这是否有帮助,但你尝试过在使用 close() 前先使用 shutdown() 吗? - Hasturkun
我刚试过了,使用 shutdown(); close(); 的行为是一样的,但是使用 shutdown(); sleep(1); close(); 实际上会优雅地关闭连接。所以似乎它会创建一个竞争条件,当套接字的另一侧“快速获得其机会”时,它就没问题了。因此这是不想要的,我不能调用 sleep(...) - kuba
1个回答

2

使用有状态的套接字(Unix域或TCP),区分“没有可用数据”和另一端关闭套接字的最佳方法是首先使用select(),传递readfds(参见man 2 select)。仅当select指示读事件时,才尝试在套接字上进行读取(read())。如果读取的字节数为0,则表示套接字已关闭(连接由对等方重置)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接