简体   繁体   中英

Unix IPC socket: closing one end without reading from it

I have a parent process and a forked child process, and they share a Unix-domain IPC socket, created with socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) . Both of the processes close one end of the socketpair, and save the other end into the sock variable. After that they do this:

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);
  }
}

Parent process writes some data into the socket, and the child doesn't read it. Instead the child closes the socket. Now my concern is that read in the parent process fails with ECONNRESET (Connection reset by peer), while I would expect that it will return "0" indicating end of stream. Because the other end of the socket was gracefully closed by calling close .

Now, I understand that behaviour (closing the socket without reading pending data generates ECONNRESET), but where is this documented? man read says nothing about ECONNRESET, but it mentions:

Other errors may occur, depending on the object connected to fd

The man page for unix domain sockets only says:

ECONNRESET: Remote socket was unexpectedly closed.

But since Unix-domain sockets are a local IPC thing, I suppose it could be much more specific about the circumstances when this error can happen.

My "deeper thoughts" are something like this: If the specification say eg close will generate end-of-stream mark only if there is no data to read from the socket, how does it know if the other process isn't just about to write some? Doesn't that create a race condition? How does the kernel know if the connection is going to be closed gracefully or not?

With stateful sockets (unix domain or tcp), the best way to distinguish "no data available" and a close of the socket on the other end, is to first use select(), passing a readfds (see man 2 select). If, and only if the select indicates a read event, then try to read() on the socket. If the number of bytes read is 0, that means the socket was closed (connection reset by peer).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM