csocketstcp

Using poll() for a TCP server in C


For a school assignment we have to make a sensor gateway which has an input from multiple sensors that connect through TCP. We recieved a library that we can use for the TCP sockets. Whenever a sensor node gets disconnected, it has to be logged and certain data functions have to be called. I used poll() to multiplex the I/O of the gateway but the problem is, that it is not working correctly. I made a prototype of my gateway connection code below. It has the same problem so I presume I'm doing something wrong with poll() but I don't know what.

Here is my code for the server:

int main( void )
{
Socket server; 
Socket client[6];
int client_count = 0;
struct pollfd poll_list[7];

// open server socket
server = tcp_passive_open( PORT );
poll_list[0].fd = get_socket_descriptor( server ); 
poll_list[0].events = POLLIN;

while( 1 ) {    
  int retval, i;

  retval = poll(poll_list, client_count+1, 5000);
  if (retval > 0) {
      if (poll_list[0].revents && POLLIN > 0) {
          client[client_count] = tcp_wait_for_connection( server );
          poll_list[client_count+1].fd = get_socket_descriptor(client[client_count]);
          poll_list[client_count+1].events = POLLIN;
          client_count++;
      }    
      for (i=0; i<client_count+1;i++) 
  {
          if ( poll_list[i+1].revents & POLLIN)) 
      {
      printf("New message recieved.");
              tcp_receive(client[i], buffer, BUFFSIZE); 
      fflush(stdout);

          }
      if ( poll_list[i+1].revents & POLLHUP) 
      {
      printf("Client disconnected.");
              poll_list[client_count+1].fd = -1;
              poll_list[client_count+1].events = 0;
      fflush(stdout);   
          }
      }
  }
}

tcp_close( &server ); 
return 0;
}

Here is the code for the client:

int main( void ) {
Socket client;
char msg[] = "Hello there! Anyone?";

// open TCP connection to the server; server is listening to SERVER_IP and PORT
client = tcp_active_open( PORT, SERVER_IP ); 

// send msg to server
tcp_send( client, (void *)msg, strlen(msg)+1 ); 

printf("\n");  

// exit
tcp_close( &client );
return 1;
}

EDIT: The functions of the library files:

Socket tcp_passive_open(int port);
/* Creates a new TCP socket and opens the socket in 'passive listening mode' (waiting for an 
active connection setup request). The socket is bound to port number 'port' and to any 
IP address of the PC. The number of pending connection setup requests is set to the 
maximum. The newly created socket is return as the function result. This function is 
typically called by a server. */


Socket tcp_active_open(int remote_port, char *remote_ip );
/* Creates a new TCP socket and opens a TCP connection to a socket on the PC with IP address 
'remote_ip' on port 'remote_port'. The IP address that the host PC has to use to connect 
to the remote PC, is not defined (it is left to the system to choose an available IP       interface). 
The newly created socket is return as the function result. This function is typically 
called by a client. */


Socket tcp_wait_for_connection( Socket socket );
/* Puts the socket 'socket' in a blocking waiting mode. The function will only return 
when an incoming TCP connection setup request is received. The remote socket (the 
remote IP address and port number) that initiated the connection request is returned 
as the function result.  */


void tcp_close( Socket *socket );
/* The socket 'socket' is closed and any allocated resources are freed. */


void tcp_send(Socket socket, void *buffer, int bufsize );
/* The function initiates a send command on the socket 'socket'. Recall that the 
send command might block. In total 'bufsize' bytes of data in 'buffer' will be send. 
Of course, the socket 'socket' needs to be connected to a remote socket before this 
function can be called.  */

int tcp_receive (Socket socket, void* buffer, int bufsize);
/* The function initiates a receive command on the socket 'socket'. Recall that the 
receive command might block. Pending data in 'socket' will be copied to 'buffer'. The 
function returns the number of bytes that were really copied to 'buffer', which might 
be less than 'bufsize'. No more than 'bufsize' bytes however will be copied. Of course, 
the socket 'socket' needs to be connected to a remote socket before this function can 
be called.*/


char * get_ip_addr( Socket socket );
/* Returns the IP address to which the socket 'socket' is bound. The IP address is 
returned as a string. */

int get_port( Socket socket ); 
/* Returns the port number to which the socket 'socket' is bound. */

int get_socket_descriptor( Socket socket ); 
/* Returns the socket descriptor to which the socket 'socket' is bound. */

The output that I get is like:

New message recieved.New message recieved.New message received....

Instead of:

New message received.
Client disconnected.

It keeps saying that there is a new message, but there is none. This is very frustrating because in the actual gateway, the program is processing data that isn't there. Does anyone know how I can fix this?

Thanks in advance.


Solution

  • I hope this isn't too late, but I believe the tcp_receive() returns the amount of bytes that are read. Instead of checking the POLLHUP, you can check if the value you receive is equal to zero. If so, you can assume the connection is closed.

    if (poll_list[i+1].revents & POLLIN)){
        if(tcp_receive(client[i], buffer, BUFFSIZE) == 0){
            printf("Client disconnected.\n");
            poll_list[client_count+1].fd = -1;
            poll_list[client_count+1].events = 0;
        }else{
            printf("New message recieved.\n");
        }
        fflush(stdout);
    }