in reply to Re: Socket dilemma - sending EOF
in thread Socket dilemma - sending EOF

Stevens doesn't say shutdown-based transactions violate good practices, I don't think.

shutdown(1) forces half of the connection to be closed. I often use this for the same purpose as the original poster. The other end has no obligation to close the other half when this happens. Stevens is talking about close(), which is a different beast. It decrements a reference count, and if it reaches zero, shuts down both halves of the connection. shutdown doesn't bother with reference counts; it immediately forces one or both halves shut.

You should never close a connection before reading out all of the data (that'll lock up the port for a very long time and may send a broken pipe signal to the other end.) I assume the same thing would happen if you did shutdown(0) with data in transit. But it's fine to shutdown(1) the half you're writing to; it's then the problem of the other end to read everything out and take that half down.

But in answer to the original question, you're not going to be able to send an intermediate EOF. You'll either have to change the protocol (4-byte network byte-order chunk sizes work fine, with zero meaning end-of-message), or make new connections. There are nasty little wrinkles in TCP that you could try to exploit (eg out of band data), but that'll do you much more harm than good. And it's still a protocol change, just at a different level.

But I don't really understand what was meant by "the third party server closes the socket and therefore I cannot read their response". As long as they write the full response to the socket before calling close(), it'll be fine -- you can read their response, get an EOF, and do a close() yourself. Are you getting a broken pipe? What happens?

Just for illustration, here's a simple shutdown-based handshake (yes, I just wanted to see if I could do it).perl -MIO::Socket -we 'sub S{$l=IO::Socket::INET->new(LocalPort=>9123,Listen=>5);$s=$l->accept();print "rS:$_" while(<$s>); print $s "what?\n";} sub C{sleep 1;$c=IO::Socket::INET->new(PeerAddr=>"localhost:9123"); print $c "hello\n"; shutdown($c,1); print "rC:$_" while(<$c>);} exit(fork?S:C)'

Update: Wow, I was way too argumentative in my initial response. It looked like I was disagreeing with lots of stuff I fully agree with (eg how half-closes are realized in TCP packets). I rewrote the first sentence to be more specific.

Replies are listed 'Best First'.
Re: Re: Re: Socket dilemma - sending EOF
by Nuke (Scribe) on May 18, 2002 at 00:21 UTC
    Good points. I'm not sure I totally agree. Shutdown(1) forces a close of half the socket. That's fine and inline with what I said. In order for this to happen, on the TCP level, a FIN must be sent to the other end. That end will answer back with an ACK of it's own, which completes the shutdown of HALF of the socket.


    My next statement is a bit misleading I guess. You are correct that the other side does not have to initiate a shutdown of the other half of the socket right away. However, it's probably better to keep both halves of the socket open until you're done sending and receiving. This would allow multiple requests in a single session. That may not be required NOW, but experience has taught me that those who dictate what you need to code will oftimes ask for things you thought you'd never need.

    But I guess it's moot, because the bottom line is the protocol is going to have to change, since the other end is apparently enterpreting the shutdown of half the socket as a hard close of the socket.

    I'll admit to one thing... I've never actually used IO::socket, and am making some assumptions based on documentation I can find. If I'm way off, please tell me exactly how. I think I've got it right though.

    Nuke
    nuke@nuke3d.com
    <a href="http://www.nuke3d.com"=p:a.nuke3d.com

      I have no argument with the idea that forcing EOF with shutdown isn't a great approach in terms of flexibility. But it's a great quick & dirty solution. Especially since it isn't that easy in perl to wrap streams, so if you want to simply replace an input filehandle with a socket connection that behaves pretty much the same way (but still be able to report back a result to the client), it's a good trick.