9

In the client, I have a

close(sockfd)

where sockfd is the socket that's connected to the server. In the server I've got this:

if (sockfd.revents & POLLERR ||
    desc_set[i].revents & POLLHUP || desc_set[i].revents & POLLNVAL) { 
  close(sockfd.fd); 
  printf("Goodbye (connection closed)\n");
}

Where sockfd is a struct pollfd, and sockfd.fd is the file descriptor of the client's socket.

When the client closes the socket like I put up there, the server doesn't seem to detect it with the second code (desc_set[i].revents & POLLHUP, etc.).

Does anyone know what's the problem?

dasen
  • 91
  • 2

2 Answers2

11

Sounds like you've managed to half close the connection from the client side. In this state the connection can still send data in one direction, i.e. it operates in half-duplex mode. This is by design and would allow your server to finish replying to whatever the client sent. Typically this would mean completing a file transfer and calling close(), or answering all of the aspects of the query. In the half-closed state you can still quite sensibly send data to the side that has already called close(). In your server you will see eof if you try to read though. close() just means "I'm done sending, finish up whatever I asked for".

POLLHUP, POLLERR and POLLNVAL only checks the output side of the local connection, which is still valid here. There's a POLLRDHUP, which is a GNU extension that should detect the other side closing, but the tests you're doing are only checking if it's still writable, not if it's still readable.

See also this question, which is talking about java, but still very related.

Community
  • 1
  • 1
Flexo
  • 87,323
  • 22
  • 191
  • 272
  • Sorry for making such a newbie question, but how do I include that GNU extension into my code? – dasen Nov 12 '10 at 16:05
  • #define _GNU_SOURCE before any #includes will do it. Making the server call close() of it's own free will once it's served the request is a much, much nicer way though. – Flexo Nov 12 '10 at 16:07
  • I've used that GNU extension, but it still doesn't close on the server side. – dasen Nov 12 '10 at 16:11
  • Hmm, I'm not sure on the GNU extension to be honest, I've never actually used. I only spotted it whilst checking the manpages to write this answer. Question 2.1 of: http://www.faqs.org/faqs/unix-faq/socket/ talks about testing to see if the socket is closed though. – Flexo Nov 12 '10 at 16:18
  • Ok, I did it, I followed the link you sent and in it I saw the following which I added: rc = read(sock,buf,sizeof(buf)); if (rc == 0 ) { close(sock); } – dasen Nov 12 '10 at 17:08
  • POLLRDHUP is a *Linux* extension rhat requires a GNU compilation flag. – user207421 Oct 30 '19 at 10:38
6

A remote close or output shutdown is neither an error nor a hangup nor an invalid state. It is a read event such that read() will return zero. Just handle it as part of your normal read processing.

BTW your test condition above should read sockfd.revents & (POLLERR|POLLHUP|POLLNVAL).

user207421
  • 305,947
  • 44
  • 307
  • 483
  • 1
    Right - a graceful `close()` is signalled by `read()` returning 0, so it is signalled by `POLLIN`. – caf Nov 16 '10 at 05:42