0

I wrote in C a server - client chatroom.

The server creates a new pthread for every new connection to a client, this pthread waits for a message to receive, and sends this message to all the other clients (using a array of all the file descriptors). If a client wants to quit he informs the server and he will terminate the pthread and delete the file descriptor from the array

This works fine !, but:

if a client disconnects unexpected, by closing the terminal for example, the server won't delete the file descriptor from the array and when an other client wants to send a message i have an error because the pthread tries to send the message to a fd which isn't a connection any more

Now my question:

How can in test if the file descriptor of a client's socket is still active before i send a message ?

the part of my code (from the pthread):

for(i=0; i<*p_Nbr_Clients; i++){ // send the message to all the other clients
        if (fd_array[i] != fd){ // <- i want to test the fd here
                 if ( send(fd_array[i], msg, strlen(msg), 0) == -1 ){
                     perror("Serveur: send");
                 }
        }
}
Marius Küpper
  • 257
  • 1
  • 4
  • 15
  • Can you post or tell how you are testing which client has sent the message to server? – Chandru Dec 23 '14 at 13:02
  • @Chandru every client has his own thread on the server, a thread takes only care of one client, and the thread knows the fd of his client – Marius Küpper Dec 23 '14 at 13:06
  • You should cache the return value of strlen(msg) outside the for loop because it iterates through the msg array for every participant which is fairly inefficient. – Géza Török Dec 23 '14 at 14:04

2 Answers2

2

There is no standalone api to check whether socket is closed. Just try to send data to that socket.

send will return -1 if you write to a closed socket. and errno will be set to appropriately. You may got EBADF or ECONNRESET i guess. Check (Check connection open or closed ?(in C in Linux)) and (How to find out if a socket is closed)

for(i=0; i<*p_Nbr_Clients; i++){ // send the message to all the other clients
        if (fd_array[i] != fd){ // <- i want to test the fd here
                 if ( send(fd_array[i], msg, strlen(msg), 0) == -1 ){
                     //perror("Serveur: send");
                     // something wrong, check errno to see more detail
                     // you need to include <errno.h> to use errno
                     close(fd_array[i]);
                     fd_array[i] = -1;// or something you define as not open
                 }
        }
}
Community
  • 1
  • 1
D3Hunter
  • 1,329
  • 10
  • 21
  • so should i make a try{send} catch ... ? because the error will destroy the server application – Marius Küpper Dec 23 '14 at 13:16
  • There is no try catch in C. I have add some comment to the answer, check that. – D3Hunter Dec 23 '14 at 13:25
  • If the socket was `close()`ed locally you might get `EBADF`. If it had been closed remotely (which is the OP's question) you'll get `EPIPE` or even a `SIGPIPE` which's default behaviour is to end the process. – alk Dec 23 '14 at 13:57
  • @alk. You just reversed those two. From `man send` : `EPIPE The local end has been shut down on a connection oriented socket` – D3Hunter Dec 23 '14 at 14:00
2

Check the return value of the recv().

If the user terminated abnormally then return value should be zero 0.

Based on that you can close fd easily.

if(recv(fd,buffer,length,flag) == 0)
      close(fd);
Chandru
  • 1,306
  • 13
  • 21