Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is writing a closed TCP socket worse than reading one?

When you read a closed TCP socket you get a regular error, i.e. it either returns 0 indicating EOF or -1 and an error code in errno which can be printed with perror.

However, when you write a closed TCP socket the OS sends SIGPIPE to your app which will terminate the app if not caught.

Why is writing the closed TCP socket worse than reading it?

like image 874
Robert S. Barnes Avatar asked Feb 07 '10 08:02

Robert S. Barnes


People also ask

When should I close TCP socket?

A TCP socket that is connected should not be closed until the connection has been shut down. To gracefully shut down a socket first call FreeRTOS_shutdown(), then wait for read attempts on the socket to return -pdFREERTOS_ERRNO_EINVAL, indicating that the socket is no longer connected.

What can happen if you do not close a socket when you finish using it?

One way or another, if you don't close a socket, your program will leak a file descriptor. Programs can usually only open a limited number of file descriptors, so if this happens a lot, it may turn into a problem.

Why does TCP need two sockets?

The reason is that TCP has two different kinds of state that you want to control, whereas UDP has only one.

Is TCP socket safe?

No, it's not "secure".


2 Answers

+1 To Greg Hewgill for leading my thought process in the correct direction to find the answer.

The real reason for SIGPIPE in both sockets and pipes is the filter idiom / pattern which applies to typical I/O in Unix systems.

Starting with pipes. Filter programs like grep typically write to STDOUT and read from STDIN, which may be redirected by the shell to a pipe. For example:

cat someVeryBigFile | grep foo | doSomeThingErrorProne

The shell when it forks and then exec's these programs probably uses the dup2 system call to redirect STDIN, STDOUT and STDERR to the appropriate pipes.

Since the filter program grep doesn't know and has no way of knowing that it's output has been redirected then the only way to tell it to stop writing to a broken pipe if doSomeThingErrorProne crashes is with a signal since return values of writes to STDOUT are rarely if ever checked.

The analog with sockets would be the inetd server taking the place of the shell.

As an example I assume you could turn grep into a network service which operates over TCP sockets. For example with inetd if you want to have a grep server on TCP port 8000 then add this to /etc/services:

grep     8000/tcp   # grep server

Then add this to /etc/inetd.conf:

grep  stream tcp nowait root /usr/bin/grep grep foo

Send SIGHUP to inetd and connect to port 8000 with telnet. This should cause inetd to fork, dup the socket onto STDIN, STDOUT and STDERR and then exec grep with foo as an argument. If you start typing lines into telnet grep will echo those lines which contain foo.

Now replace telnet with a program named ticker that for instance writes a stream of real time stock quotes to STDOUT and gets commands on STDIN. Someone telnets to port 8000 and types "start java" to get quotes for Sun Microsystems. Then they get up and go to lunch. telnet inexplicably crashes. If there was no SIGPIPE to send then ticker would keep sending quotes forever, never knowing that the process on the other end had crashed, and needlessly wasting system resources.

like image 131
Robert S. Barnes Avatar answered Oct 20 '22 06:10

Robert S. Barnes


Usually if you're writing to a socket, you would expect the other end to be listening. This is sort of like a telephone call - if you're speaking, you wouldn't expect the other party to simply hang up the call.

If you're reading from a socket, then you're expecting the other end to either (a) send you something, or (b) close the socket. Situation (b) would happen if you've just sent something like a QUIT command to the other end.

like image 36
Greg Hewgill Avatar answered Oct 20 '22 06:10

Greg Hewgill