Is it safe to read from pipe OR socketpair with on

2019-08-29 02:59发布

问题:

Consider the following EXAMPLE code:

#include <sys/socket.h>

int main()
{
    int sv[ 2 ] = { 0 };
    socketpair( AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, sv );

    for( unsigned ii = 0; ii < 5; ++ii )
    {
        int* msg = new int( 123 );
        if( -1 == send( sv[ 0 ], &msg, sizeof(int*), MSG_NOSIGNAL ) )
        {
            delete msg;
        }
    }

    close( sv[0] );
    sleep( 1 );

    int* msg = 0;
    int r;
    while( ( r = read( sv[ 1 ], &msg, sizeof(int*) ) ) > 0 )
    {
        delete msg;
    }

    return 0;
}

Obviously, the code works fine, but it doesn't mean it's not UB.

Couldn't find anything in the man pages, which guarantees, that when sv[ 0 ] is closed, the read will still be able to read everything from sv[ 1 ], sent by the send.


Maybe the question could be asked like this - as read returns 0 for EOF and as the socketpair is SOCK_STREAM, I expect the EOF will be "hit" once everything is read from the socket and the other side is closed. Is this correct?

回答1:

AFAIK it can work, but smells UB.

The correct way is the graceful shutdown :

  • shutdown(s, 1) or (better shutdown(s, SHUT_WR))
  • read until eof on input
  • only then call close.

(References : http://msdn.microsoft.com/en-us/library/windows/desktop/ms738547%28v=vs.85%29.aspx, Graceful Shutdown Server Socket in Linux)

Edit :

After reading R.. comment, I wondered if I was not a little confused, did some tests and read documentation again. And ... I now think what I said is true for general socket usage (include AF_INET sockets), but not for the special AF_INET socketpair.

My test was put a little more stress on the system, since I send 8 packets of 1024 bytes on a FreeBSD 9 system. I stopped there because sending more would have blocked. And after the close on sv[0] I could successfully read my 8 packets.

So it works on different kernels, but could not find a valid reference for it except that AF_UNIX sockets do not support OOB data.

I could also confirm that using shutdown, works fine.

Conclusion : As far as I am concerned, I would stick to graceful shutdown for closing a socket, but mostly because I do not want to think about the underlying protocol.

Hope somebody else with more knowledge could give a piece of reference documentation