8

So let me simplify the code I'm working on:

int fd = socket(...);
int client = accept(fd, ...);
while (true) {
    int bytes_read = recv(client, ...);
    if (bytes_read == 0) {
        break;
    }
};

At this point I already know that the client is disconnected (recv returned 0). But do I still have to call

close(client);

?

freakish
  • 54,167
  • 9
  • 132
  • 169
  • Well I think you need to do so, since that will [I think] create a memory leaks since you do not close the file descriptor. – kaldoran Apr 12 '17 at 12:06
  • 2
    If you don't call close(), and keep creating new sockets (e.g. via accept()), then eventually your process's sockets-table will fill up with leftover sockets, and then your process won't be able to create anymore, so accept(), socket(), etc will all fail with errno=EMFILE, and then your program will not work very well anymore :( – Jeremy Friesner Apr 12 '17 at 14:56

3 Answers3

13

Yes.

When you recv() 0 bytes, that's the kernel's way of letting you know that the remote host has shut down their sending side of the connection. It's possible that they still have the socket open and could receive more data you send (but not reply).

When you call close() on a TCP socket, you are doing two things:

  1. Shutting down the local side of the socket, letting the remote host know that you're also finished transmitting. Without doing so, you potentially leave the clients hanging, waiting for you to send more data.
  2. Closing the file descriptor. This releases the entry in your process open file table. Without doing so, you are wasting resources and could find yourself out of memory or available file descriptors. Most every OS has a hard limit on the number of file descriptors (or handles) that a process can have open at one time.
Jonathon Reinhart
  • 132,704
  • 33
  • 254
  • 328
  • Ad1: the client (remote host) does not need to be informed(it is already dead), but the entry in the connection-table needs to be deallocated (it will probably first stay in a time-wait state for some time) This is automatically dealt with in your (2) : it is handled via the close(fd) – wildplasser Apr 12 '17 at 12:27
  • @wildplasser Re: 1 I think you missed my point. The client may not be "dead" - he could have only called `shutdown(fd, SHUT_WR)` and could be still waiting for more data from the server. In this case he *does* need to be informed. – Jonathon Reinhart Apr 12 '17 at 12:33
  • That is correct; it could be half-closed. But I fully agree with you: calling close(fd) is the way to go. – wildplasser Apr 12 '17 at 12:37
  • @Jonathon Receiving an EOF, calling shutdown is pointless since the other side has already closed the connection or has at least shutdown its sending part of the connection. Invoking shutdown() would close the other half of the connection the same way as close() will do anyways. Regarding "needs to be informed" this will also happen with close(), no need to call shutdown(). – Meixner Apr 13 '17 at 06:35
  • Thanks @Meixner, but why was that comment directed at me? I'm well aware that `close()` implies `shutdown()`. Nowhere did I suggest that calling `shutdown` was required. – Jonathon Reinhart Apr 13 '17 at 10:56
1

You need to close the descriptor to release the resources bound to it.

Meixner
  • 615
  • 5
  • 8
1

The answer is yes. The reason is that accept() allocates memory, close() frees that memory.

Imagine a theoretical situation where your code is in a loop and that every time you call accept(), it allocates 1GB of RAM (pretend that it is a really inefficient socket library :-) ). Whenever you call close(), it frees up 1GB of RAM. If you never call close(), how many times round the loop will accept() happen before you run out of memory?

Of course accept() only allocates a small chunk of memory, but eventually, you will run out of memory, unless you do something about it.

Neil
  • 11,059
  • 3
  • 31
  • 56
  • 2
    The memory itself isn't really through issue. It's the limit on open file descriptors that's going to bite you. I think you need to re-word your answer because it is not clear that this sentence is hypothetical: *"Every time you call accept(), it allocates 1GB of RAM."* – Jonathon Reinhart Apr 12 '17 at 12:16