'How to find the socket connection state in C?

I have a TCP connection. Server just reads data from the client. Now, if the connection is lost, the client will get an error while writing the data to the pipe (broken pipe), but the server still listens on that pipe. Is there any way I can find if the connection is UP or NOT?



Solution 1:[1]

You could call getsockopt just like the following:

int error = 0;
socklen_t len = sizeof (error);
int retval = getsockopt (socket_fd, SOL_SOCKET, SO_ERROR, &error, &len);

To test if the socket is up:

if (retval != 0) {
    /* there was a problem getting the error code */
    fprintf(stderr, "error getting socket error code: %s\n", strerror(retval));
    return;
}

if (error != 0) {
    /* socket has a non zero error status */
    fprintf(stderr, "socket error: %s\n", strerror(error));
}

Solution 2:[2]

The only way to reliably detect if a socket is still connected is to periodically try to send data. Its usually more convenient to define an application level 'ping' packet that the clients ignore, but if the protocol is already specced out without such a capability you should be able to configure tcp sockets to do this by setting the SO_KEEPALIVE socket option. I've linked to the winsock documentation, but the same functionality should be available on all BSD-like socket stacks.

Solution 3:[3]

TCP keepalive socket option (SO_KEEPALIVE) would help in this scenario and close server socket in case of connection loss.

Solution 4:[4]

There is an easy way to check socket connection state via poll call. First, you need to poll socket, whether it has POLLIN event.

  1. If socket is not closed and there is data to read then read will return more than zero.
  2. If there is no new data on socket, then POLLIN will be set to 0 in revents
  3. If socket is closed then POLLIN flag will be set to one and read will return 0.

Here is small code snippet:

int client_socket_1, client_socket_2;
if ((client_socket_1 = accept(listen_socket, NULL, NULL)) < 0)
{
    perror("Unable to accept s1");
    abort();
}
if ((client_socket_2 = accept(listen_socket, NULL, NULL)) < 0)
{
    perror("Unable to accept s2");
    abort();
}
pollfd pfd[]={{client_socket_1,POLLIN,0},{client_socket_2,POLLIN,0}};
char sock_buf[1024]; 
while (true)
{
    poll(pfd,2,5);
    if (pfd[0].revents & POLLIN)
    {
        int sock_readden = read(client_socket_1, sock_buf, sizeof(sock_buf));
        if (sock_readden == 0)
            break;
        if (sock_readden > 0)
            write(client_socket_2, sock_buf, sock_readden);
    }
    if (pfd[1].revents & POLLIN)
    {
        int sock_readden = read(client_socket_2, sock_buf, sizeof(sock_buf));
        if (sock_readden == 0)
            break;
        if (sock_readden > 0)
            write(client_socket_1, sock_buf, sock_readden);
    }
}

Solution 5:[5]

I had a similar problem. I wanted to know whether the server is connected to client or the client is connected to server. In such circumstances the return value of the recv function can come in handy. If the socket is not connected it will return 0 bytes. Thus using this I broke the loop and did not have to use any extra threads of functions. You might also use this same if experts feel this is the correct method.

Solution 6:[6]

Very simple, as pictured in the recv.

To check that you will want to read 1 byte from the socket with MSG_PEEK and MSG_DONT_WAIT. This will not dequeue data (PEEK) and the operation is nonblocking (DONT_WAIT)

while (recv(client->socket,NULL,1, MSG_PEEK | MSG_DONTWAIT) != 0) {
    sleep(rand() % 2); // Sleep for a bit to avoid spam
    fflush(stdin);
    printf("I am alive: %d\n", socket);
}

// When the client has disconnected, this line will execute
printf("Client %d went away :(\n", client->socket);

Found the example here.

Solution 7:[7]

get sock opt may be somewhat useful, however, another way would to have a signal handler installed for SIGPIPE. Basically whenever you the socket connection breaks, the kernel will send a SIGPIPE signal to the process and then you can do the needful. But this still does not provide the solution for knowing the status of the connection. hope this helps.

Solution 8:[8]

You should try to use: getpeername function.

now when the connection is down you will get in errno: ENOTCONN - The socket is not connected. which means for you DOWN.

else (if no other failures) there the return code will 0 --> which means UP.

resources: man page: http://man7.org/linux/man-pages/man2/getpeername.2.html

Solution 9:[9]

On Windows you can query the precise state of any port on any network-adapter using: GetExtendedTcpTable

You can filter it to only those related to your process, etc and do as you wish periodically monitoring as needed. This is "an alternative" approach.

You could also duplicate the socket handle and set up an IOCP/Overlapped i/o wait on the socket and monitor it that way as well.

Solution 10:[10]

#include <sys/socket.h>
#include <poll.h>
...

int client = accept(sock_fd, (struct sockaddr*)&address, (socklen_t*)&addrlen);
pollfd pfd = {client, POLLERR, 0}; // monitor errors occurring on client fd
...
while(true)
{
   ...
   if(not check_connection(pfd, 5))
   {
        close(client);
        close(sock[1]);
        if(reconnect(HOST, PORT, reconnect_function))
            printf("Reconnected.\n");
        pfd = {client, POLLERR, 0};
   }
   ...
}
...
bool check_connection(pollfd &pfd, int poll_timeout)
{
    poll(&pfd, 1, poll_timeout);
    return not (pfd.revents & POLLERR);
}

Solution 11:[11]

you can use SS_ISCONNECTED macro in getsockopt() function. SS_ISCONNECTED is define in socketvar.h.

Solution 12:[12]

For BSD sockets I'd check out Beej's guide. When recv returns 0 you know the other side disconnected.

Now you might actually be asking, what is the easiest way to detect the other side disconnecting? One way of doing it is to have a thread always doing a recv. That thread will be able to instantly tell when the client disconnects.