Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't this server I wrote detect that the client has closed the socket to it?

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?

like image 749
dasen Avatar asked Nov 12 '10 15:11

dasen


People also ask

How do you know if a socket is closed?

The most obvious way to accomplish this is having that process call read on the socket for a connection and check whether read returns 0 (i.e. reads zero bytes from the socket), in which case we know that the connection has been closed.

How do you close a socket from a client?

When you have finished dealing with the client you must close() that socket, (that's close(cfd) in your terminology). You may also shutdown() the socket - that will influence how the socket is closed at a TCP level.


2 Answers

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).

like image 123
user207421 Avatar answered Oct 14 '22 09:10

user207421


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.

like image 24
Flexo Avatar answered Oct 14 '22 11:10

Flexo