【问题标题】:Unix IPC socket: closing one end without reading from itUnix IPC套接字:关闭一端而不读取它
【发布时间】:2012-04-30 16:26:00
【问题描述】:

我有一个父进程和一个分叉的子进程,它们共享一个使用socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) 创建的 Unix 域 IPC 套接字。两个进程都关闭套接字对的一端,并将另一端保存到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 的对象

man page for unix domain sockets 只说:

ECONNRESET:远程套接字意外关闭。

但由于 Unix 域套接字是本地 IPC 事物,我想它可能会更具体地说明可能发生此错误的情况。

我的“更深层次的想法”是这样的:如果规范说例如close 只有在没有数据要从套接字读取的情况下才会生成流结束标记,它如何​​知道其他进程是否只是要写入一些数据?这不会造成竞争条件吗?内核如何知道连接是否会正常关闭?

【问题讨论】:

  • 不确定这是否有帮助,但您是否尝试过在close() 之前使用shutdown()
  • 我刚刚尝试过,使用shutdown(); close(); 的行为相同,但使用shutdown(); sleep(1); close(); 实际上可以优雅地关闭连接。所以它似乎创造了一个竞争条件,当套接字的另一端“轮到”足够快时,它会没事的。所以这是不需要的,我不能打电话给sleep(...)

标签: linux sockets unix ipc pipe


【解决方案1】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-07-30
    • 1970-01-01
    • 2014-07-24
    • 2014-08-31
    • 1970-01-01
    • 2017-09-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多