251

In C, I understood that if we close a socket, it means the socket will be destroyed and can be re-used later.

How about shutdown? The description said it closes half of a duplex connection to that socket. But will that socket be destroyed like close system call?

tshepang
  • 12,111
  • 21
  • 91
  • 136

9 Answers9

226

This is explained in Beej's networking guide. shutdown is a flexible way to block communication in one or both directions. When the second parameter is SHUT_RDWR, it will block both sending and receiving (like close). However, close is the way to actually destroy a socket.

With shutdown, you will still be able to receive pending data the peer already sent (thanks to Joey Adams for noting this).

red0ct
  • 4,840
  • 3
  • 17
  • 44
Matthew Flaschen
  • 278,309
  • 50
  • 514
  • 539
  • 1
    But if the second parameter is 0 or 1, shutdown will not close the socket, isn't it? Therefore, I can not re-use this socket immediately because it is not freed. Is that right? –  Nov 11 '10 at 23:42
  • 1
    @tsubasa, that's correct. Again, to free the socket, you should use `close`. – Matthew Flaschen Nov 11 '10 at 23:43
  • 2
    Correct. If you shut down only writing on a socket, you can still receive data on it, and if you shut down only reading, you can still send data on it. Only when it is shut down both ways will it be destroyed. (But it is *not* necessary to call `close(fd)` after using `shutdown` to disable both reading and writing, whether you did that in one call or two.) – zwol Nov 11 '10 at 23:46
  • 25
    Keep in mind, even if you close() a TCP socket, it won't necessarily be immediately reusable anyway, since it will be in a TIME_WAIT state while the OS makes sure there's no outstanding packets that might get confused as new information if you were to immediately reuse that socket for something else. – alesplin Nov 11 '10 at 23:46
  • 5
    I have to correct myself: I had been under the impression that shutting down a socket both ways was equivalent to calling `close` on it, but I just tried it, and it's not true. The file descriptor remains valid (un-reusable) till you call `close`. I'm not sure what *use* a shut-down-both-ways socket is, but maybe there is something that can be done with it besides closing it. – zwol Nov 11 '10 at 23:58
  • 114
    Big difference between shutdown and close on a socket is the behavior when the socket is shared by other processes. A shutdown() affects *all* copies of the socket while close() affects only the file descriptor in one process. – Zan Lynx Nov 12 '10 at 00:24
  • 7
    One reason you may want to use `shutdown` both directions but not `close` is if you made a `FILE` reference to the socket using `fdopen`. If you `close` the socket, a newly opened file could be assigned the same fd, and subsequent use of the `FILE` will read/write the wrong place which could be very bad. If you just `shutdown`, subsequent use of the `FILE` will just give errors until `fclose` is called. – R.. GitHub STOP HELPING ICE Nov 12 '10 at 04:22
  • 34
    The comment about TIME_WAIT is incorrect. That applies to ports, not to sockets. You can't reuse sockets. – user207421 Nov 12 '10 at 08:53
  • @Zack Do you have any sort of reference for this? I would love to believe this, but don't want to run out of file descriptors if I start shutting down sockets (one part at a time) and end up not cleaning them from the file descriptor table. – Sergey L. Oct 09 '12 at 13:13
  • 3
    @SergeyL. What I said in my first comment was wrong. I tested it, and you do in fact have to `close` the socket to clear its slot in the file descriptor table. `shutdown` both ways does *not* do that. – zwol Oct 09 '12 at 15:56
  • 60
    -1. Both this post and the link omit an important conceptual reason to want to use `shutdown`: to signal EOF to the peer and still be able to receive pending data the peer sent. – Joey Adams Jan 13 '13 at 23:39
  • @JoeyAdams, thanks. Does that apply even when you pass 2 to shutdown? – Matthew Flaschen Jan 14 '13 at 02:41
  • 6
    @MatthewFlaschen: This only applies if you use `shutdown(SD_SEND)`, as `shutdown(SD_BOTH)` will cause subsequent `recv`s to fail (though a quick test reveals that some of the `recv`s might succeed even after receiving is shutdown, since the bytes were buffered). I changed the downvote to an upvote. – Joey Adams Jan 14 '13 at 05:32
  • 1
    "shutdown() doesn't actually close the file descriptor—it just changes its usability. To free a socket descriptor, you need to use close()." - http://beej.us/guide/bgnet/output/html/singlepage/bgnet.html#closedown –  Nov 12 '14 at 01:14
  • And how `shutdown` affects a server-side socket which is currently `listen`ing and `accept`ing? Will shutdown stop only accepting or also listening? – JustAMartin Aug 11 '17 at 22:32
  • @MatthewFlaschen how about if a blocking read is being performed on a socket that has been shutdown? Will the read block forever – Bionix1441 Feb 21 '18 at 14:49
  • Not all systems allow access to pending data after `SHUT_RD`: in my testing, Linux was willing to receive data indefinitely afterwards, whereas macOS would immediately return EOF and acknowledge and drop any further traffic. – Davis Herring Oct 06 '19 at 06:38
  • the link behind "explained" is broken, and I figured out https://beej.us/guide/bgnet/ is good. – tedyyu Dec 31 '19 at 03:37
  • It‘s important to know that close() also does shutdown() implicitely, but not the other way around. If you forked, the last close() will shutdown(). Normally, close() will do (as it triggers the TCP finalization via shutdown() for you). But there might be cases, where you want to receive data from the other side although you’re done sending your stuff. In this situation, you can trigger TCP finalization with shutdown(WR), wait for some data from the other side before closing the socket via close(). In this situation close() will not trigger shutdown() again as you did it already explicitely. – Grandswiss Feb 05 '21 at 06:47
  • @ZanLynx if `close` sends an `RST` packet, then other processes sharing the same socket is still affected (indirectly), right? No local states changed, but because the remote received `RST`, the socket semantics changed. – Daniel Chin Aug 01 '23 at 20:15
205

None of the existing answers tell people how shutdown and close works at the TCP protocol level, so it is worth to add this.

A standard TCP connection gets terminated by 4-way finalization:

  1. Once a participant has no more data to send, it sends a FIN packet to the other
  2. The other party returns an ACK for the FIN.
  3. When the other party also finished data transfer, it sends another FIN packet
  4. The initial participant returns an ACK and finalizes transfer.

However, there is another "emergent" way to close a TCP connection:

  1. A participant sends an RST packet and abandons the connection
  2. The other side receives an RST and then abandon the connection as well

In my test with Wireshark, with default socket options, shutdown sends a FIN packet to the other end but it is all it does. Until the other party send you the FIN packet you are still able to receive data. Once this happened, your Receive will get an 0 size result. So if you are the first one to shut down "send", you should close the socket once you finished receiving data.

On the other hand, if you call close whilst the connection is still active (the other side is still active and you may have unsent data in the system buffer as well), an RST packet will be sent to the other side. This is good for errors. For example, if you think the other party provided wrong data or it refused to provide data (DOS attack?), you can close the socket straight away.

My opinion of rules would be:

  1. Consider shutdown before close when possible
  2. If you finished receiving (0 size data received) before you decided to shutdown, close the connection after the last send (if any) finished.
  3. If you want to close the connection normally, shutdown the connection (with SHUT_WR, and if you don't care about receiving data after this point, with SHUT_RD as well), and wait until you receive a 0 size data, and then close the socket.
  4. In any case, if any other error occurred (timeout for example), simply close the socket.

Ideal implementations for SHUT_RD and SHUT_WR

The following haven't been tested, trust at your own risk. However, I believe this is a reasonable and practical way of doing things.

If the TCP stack receives a shutdown with SHUT_RD only, it shall mark this connection as no more data expected. Any pending and subsequent read requests (regardless whichever thread they are in) will then returned with zero sized result. However, the connection is still active and usable -- you can still receive OOB data, for example. Also, the OS will drop any data it receives for this connection. But that is all, no packages will be sent to the other side.

If the TCP stack receives a shutdown with SHUT_WR only, it shall mark this connection as no more data can be sent. All pending write requests will be finished, but subsequent write requests will fail. Furthermore, a FIN packet will be sent to another side to inform them we don't have more data to send.

Earth Engine
  • 10,048
  • 5
  • 48
  • 78
  • 2
    "if you call close whilst the connection is still alive" is tautological, and it doesn't cause an RST to be sent. (1) isn't necessary. In (4), timeouts aren't necessarily fatal to the connection and don't invariable indicate you can close it. – user207421 May 06 '14 at 00:32
  • 6
    @EJP No, it isn't tautological. You can `shutdown()` the connection and then it is no longer alive. You still have the file descriptor. You can still `recv()` from the receiving buffer. And you still need to call `close()` to dispose the file descriptor. – Pavel Šimerda Jan 21 '16 at 09:58
  • 1
    This is the best answer regarding the wire format. I'd be interested about more details on shutting down with SHUT_RD. There's no TCP signalling for not expecting more data, right? Isn't there only FIN for signalling for not sending more data? – Pavel Šimerda Jan 24 '16 at 13:36
  • 4
    @PavelŠimerda Yes TCP does not signalling for not expecting more data. This should be considered in the high level protocols. In my opinion, this in general not necessory. You can close your door, but you cannot stop people putting gifts in front of the door. This is THEIR decision, not yours. – Earth Engine May 31 '16 at 22:29
  • @PavelŠimerda The tautology concerns 'call[ing] close while the connection is still alive'. Please read what is written here. I even quoted it. Not shutting it down, – user207421 Nov 03 '16 at 05:36
  • 1
    @EJP Do you have any actual arguments? Otherwise I'm not interested. – Pavel Šimerda Nov 10 '16 at 22:41
  • Note that the tcp state `CLOSE_WAIT` is a misnomer: The termination handshake will continue if the application calls `shutdown` with `SHUT_WR`. It does not necessarily have to call `close`. – not-a-user Feb 01 '17 at 14:46
  • @PavelŠimerda 'Tautological' is an argument. If you close a socket that isn't open, nothing can happen. Something can only happen if it's open. This is obvious. – user207421 Jul 27 '18 at 06:50
38

There are some limitations with close() that can be avoided if one uses shutdown() instead.

close() will terminate both directions on a TCP connection. Sometimes you want to tell the other endpoint that you are finished with sending data, but still want to receive data.

close() decrements the descriptors reference count (maintained in file table entry and counts number of descriptors currently open that are referring to a file/socket) and does not close the socket/file if the descriptor is not 0. This means that if you are forking, the cleanup happens only after reference count drops to 0. With shutdown() one can initiate normal TCP close sequence ignoring the reference count.

Parameters are as follows:

int shutdown(int s, int how); // s is socket descriptor

int how can be:

SHUT_RD or 0 Further receives are disallowed

SHUT_WR or 1 Further sends are disallowed

SHUT_RDWR or 2 Further sends and receives are disallowed

naXa stands with Ukraine
  • 35,493
  • 19
  • 190
  • 259
Milan
  • 15,389
  • 20
  • 57
  • 65
  • 10
    The two functions are for completely different purposes. The fact that the final close on a socket initiates a shutdown sequence if one hasn't already been initiated doesn't change the fact that close is for cleaning up the socket data structures and shutdown is for initiating a tcp level shutdown sequence. – Len Holgate Nov 12 '10 at 10:08
  • 27
    You can't 'use shutdown instead'. You can use it *as well.* but you must close the socket some time. – user207421 Nov 13 '10 at 00:44
19

This may be platform specific, I somehow doubt it, but anyway, the best explanation I've seen is here on this msdn page where they explain about shutdown, linger options, socket closure and general connection termination sequences.

In summary, use shutdown to send a shutdown sequence at the TCP level and use close to free up the resources used by the socket data structures in your process. If you haven't issued an explicit shutdown sequence by the time you call close then one is initiated for you.

Len Holgate
  • 21,282
  • 4
  • 45
  • 92
  • 2
    Anybody trying to achieve graceful shutdown of an HTTP connection will probably want to read the venerable Apache notes on "lingering close", found in places like http://cluster.cis.drexel.edu/manual/misc/perf-tuning.html, and maybe a more modern commentary: https://apenwarr.ca/log/20090814 – Ron Burk Oct 11 '20 at 10:11
11

I've also had success under linux using shutdown() from one pthread to force another pthread currently blocked in connect() to abort early.

Under other OSes (OSX at least), I found calling close() was enough to get connect() fail.

Toby
  • 2,039
  • 1
  • 13
  • 10
10

"shutdown() doesn't actually close the file descriptor—it just changes its usability. To free a socket descriptor, you need to use close()."1

4

Close

When you have finished using a socket, you can simply close its file descriptor with close; If there is still data waiting to be transmitted over the connection, normally close tries to complete this transmission. You can control this behavior using the SO_LINGER socket option to specify a timeout period; see Socket Options.

ShutDown

You can also shut down only reception or transmission on a connection by calling shutdown.

The shutdown function shuts down the connection of socket. Its argument how specifies what action to perform: 0 Stop receiving data for this socket. If further data arrives, reject it. 1 Stop trying to transmit data from this socket. Discard any data waiting to be sent. Stop looking for acknowledgement of data already sent; don’t retransmit it if it is lost. 2 Stop both reception and transmission.

The return value is 0 on success and -1 on failure.

J.J. Hakala
  • 6,136
  • 6
  • 27
  • 61
Neha Agrawal
  • 411
  • 4
  • 9
3

in my test.

close will send fin packet and destroy fd immediately when socket is not shared with other processes

shutdown SHUT_RD, process can still recv data from the socket, but recv will return 0 if TCP buffer is empty.After peer send more data, recv will return data again.

shutdown SHUT_WR will send fin packet to indicate the Further sends are disallowed. the peer can recv data but it will recv 0 if its TCP buffer is empty

shutdown SHUT_RDWR (equal to use both SHUT_RD and SHUT_WR) will send rst packet if peer send more data.

simpx
  • 184
  • 1
  • 11
-1

linux: shutdown() causes listener thread select() to awake and produce error. shutdown(); close(); will lead to endless wait.

winsock: vice versa - shutdown() has no effect, while close() is successfully catched.