>Hello,
>Suppose I've connected stdin and stdout to a socket
>(or maybe this was done by inetd for me). Now if I
>want to gracefully terminate the program, should I
>shutdown() BOTH stdin and stdout before closing them,
>or only one? Does it matter?
>I'm asking this because I do a shutdown on both and
>occasionally end up with sockets stuck in the FIN_WAIT_2
>state (under Solaris 2.2 - so it could be a bug :).
>This prevents me from binding to the socket again if
>my server process dies.
shutdown(2) won't fix that, its caused by close()ing the socket with unsent
data in it that doesn't get sent (including the FIN's and other little TCP
controls needed to properly terminate the connection) The fix is to set the
SO_LINGER option for the socket. Use l_linger = 0 and l_onoff = 1. The man
page will tell you l_linger is the amount of time to linger, but on most
Unixes (except for BSD 4.4 at least, I believe it was Chris Torek who mailed
me a response to a query I had about SO_LINGER a year or so ago and told me
this was fixed in 4.4) a non-zero linger time means "infinity". Which means
your process locks up when trying to close() the socket's file descriptor, or
during _exit()! Ack!
For the cleanest, bestest way to terminate a TCP connection (IMHO of course)
you want to set the SO_LINGER option as I described, then do a shutdown() when
you want to terminate the connection, wait a reasonable amount of time (where
reasonable is application dependant, I'd recommend a couple of seconds if you
are doing something like say sending "goodbye" to a user or process on the
other end over a fairly stable network, longer if you want to be more certain
the other side sees it) then you do a close() on all file descriptors that
reference that socket. Only one shutdown() is needed, it sends a FIN (or
whatever, I don't know low level TCP) to the other end which will make the
other end know you've closed gracefully without losing any data. A close
without the SO_LINGER option does essentially the same thing (but not exactly)
Then a couple seconds later you do the close(), which sends an RST, (reset
connection) to the other end, if its not closed down, this slams the door
shut. If you for some reason have some data still unsent, too bad, it is
lost.
I'm thinking that if you did a one-way shutdown (shutdown for send, but not
receive) you could then do a select on the socket and wait for it to select
true for read and thereby wait until the other end sees your shutdown for
send and responds by shutting down its end. This would provide a cleaner way
to terminate. I don't know if this works though, I haven't tried it. For
my purposes, the 5 second wait I use is long enough, if the user on the remote
end of my app doesn't see me say 'goodbye', it isn't a big deal, and if the
network is so bad they can't get a response in 5 seconds, they probably don't
want to be connected at that moment anyway, I still shutdown everything else
cleanly on my end so nothing is lost.
Kibo Turkey Greece Macedonia Perl Watcom Mason Clinton Illuminati Fnord Hastur