views:

8988

answers:

8

I have a small server program that accepts connections on a TCP or local UNIX socket, reads a simple command and, depending on the command, sends a reply. The problem is that the client may have no interest in the answer sometimes and exits early, so writing to that socket will cause a SIGPIPE and make my server crash. What's the best practice to prevent the crash here? Is there a way to check if the other side of the line is still reading? (select() doesn't seem to work here as it always says the socket is writable). Or should I just catch the SIGPIPE with a handler and ignore it?

+2  A: 

Or should I just catch the SIGPIPE with a handler and ignore it?

I believe that is right on. You want to know when the other end has closed their descriptor and that's what SIGPIPE tells you.

Sam

Sam Reynolds
+9  A: 

Generally you'd set the SIGPIPE handler to SIG_IGN if you think your app will ever write to a broken socket/pipe. It's usually much easier to handle the error on write, than to do anything intelligent in a SIGPIPE handler.

dvorak
+2  A: 

You cannot prevent the process on the far end of a pipe from exiting, and if it exits before you've finished writing, you will get a SIGPIPE signal. If you SIG_IGN the signal, then your write will return with an error - and you need to note and react to that error. Just catching and ignoring the signal in a handler is not a good idea -- you must note that the pipe is now defunct and modify the program's behaviour so it does not write to the pipe again (because the signal will be generated again, and ignored again, and you'll try again, and the whole process could go on for a long time and waste a lot of CPU power).

Jonathan Leffler
+12  A: 

Another method is to change the socket so it never generates SIGPIPE on write(). This is more convenient in libraries, where you might not want a global signal handler for SIGPIPE.

On most systems, (assuming you are using C/C++), you can do this with:

int set = 1;
setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int));
Thank you very much for this solution!
Vladimir Grigorov
A: 

The setsockopt / NOSIGPIPE solution (applied to the socket used to communicate with the client) worked great for me!

joewein
+8  A: 

I'm super late to the party, but SO_NOSIGPIPE isn't portable, and might not work on your system (it seems to be a BSD thing).

A nice alternative if you're on, say, a Linux system without SO_NOSIGPIPE would be to set the MSG_NOSIGNAL flag on your send(2) call.

sklnd
+1, Linux 2.2+ though according to man
Ray2k
A: 

MSG_NOSIGNAL is not portable. it doesn't work on Soalris. What should be the solution in case of Solaris if we dont want to handle it through signal handler.

Adil
+4  A: 

In this post I described possible solution for Solaris case when neither SO_NOSIGPIPE nor MSG_NOSIGNAL is available.

kroki
+1: interesting post.
neuro