0

I am writing a simple socket daemon witch listens to a port and reads the incoming data. It works fine until i choose to disconnect a client from the server...then it enters in a infinte loop recv() returns the last packet never gets to -1. My question is how can i detect that the client had been disconnected and close the thread/ socket el

My thread is as follows :

void * SocketHandler(void* lp){
    int * csock = (int*)lp;
    int test = 0;

    char buffer[1024];
    int  buffer_len = 1024;
    int  bytecount,ierr;
    memset(buffer,0,buffer_len);
    while (test == 0)
    {
    if ((bytecount = recv(*csock, buffer, buffer_len, 0))== -1){

        close(csock);
        free(csock);
        test++;
        return 0;
    }
    else
    {
        syslog(LOG_NOTICE,"%s",buffer);

    }
    }
    return 0;
};
opc0de
  • 11,557
  • 14
  • 94
  • 187

3 Answers3

1

A cleanly closed socket will end up in a ZERO read, while a broken connection is an error state returning -1. You need to catch the 0 return of your recv.

Eugen Rieck
  • 64,175
  • 10
  • 70
  • 92
  • Not really, when you are just reading from it you can easily end up in a state where the systems still considers the socket open. – Šimon Tóth Jun 12 '12 at 10:28
  • @Let_Me_Be I suspect you mean the "broken" state - this is ofcourse a property of TCP/IP. The "cleanly disconnected" state is guaranteed to return `0`on any sane OS – Eugen Rieck Jun 12 '12 at 10:32
  • I'm pretty sure that the Linux implementation doesn't guarantee this even on clean disconnects, but yeah, when the stars are in the right position, you should get 0. – Šimon Tóth Jun 12 '12 at 10:35
  • Well, the `0` is what is biting the OP ... on Linux. – Eugen Rieck Jun 12 '12 at 10:38
  • Oh yeah, I didn't notice the `== -1` :-D – Šimon Tóth Jun 12 '12 at 10:39
  • It works thanks.Though it seems that is not a very professional solution it's the most handy! – opc0de Jun 12 '12 at 10:41
  • @opc0de `man 2 recv` will tell you *"The return value will be 0 when the peer has performed an orderly shutdown."*, so this **is** how it should work. – Eugen Rieck Jun 12 '12 at 10:43
  • @EugenRieck `recv()` returning `-1` does not always indicate a broken connection. You must check `errno` for `EAGAIN`, `EINTR` and `EWOULDBLOCK` which are all recoverable errors. – dwalter Jun 12 '12 at 10:45
  • @dwalter I never said it did - just the other way round: A broken connection (if the OS finds out it is broken - different story) will result in an error and thus a return value of `-1`. – Eugen Rieck Jun 12 '12 at 10:48
0

What happens here is that your end may not detect the fact the socket is dead (especially, if you are just reading from it).

What you can do is set keepalive on the socket. This will turn on periodic checks of the socket liveness. But don't expect fast reactions, the default timeout is something like 20 minutes.

i = 1;
setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&i, sizeof(i));

Another option is to do your own keep-alive communication.

Šimon Tóth
  • 35,456
  • 20
  • 106
  • 151
0

recv() will indicate a proper shutdown of the socket by returning 0 (see the manpage for details). It will return -1 if and only if an error occurred. You should check errno for the exact error, since it may or may not indicate that the connection failed (EINTR, EAGAIN or EWOULDBLOCK [non-blocking sockets assumed] would both be recoverable errors).

Side note: there's no need to pass the fd of the socket as pointer and since you're returning a void * you may want to change return 0 to return NULL (just for readability).

dwalter
  • 7,258
  • 1
  • 32
  • 34