Sockets – C – Creating endless socket connection between server and client (Linux)

cclientserversocketsUbuntu

I have a simple socket program created in C (using Ubuntu), the connection works fine, server compiles and client provides the IP and port number.

But when the connection is established, the client can only send one message and then the connection closes. When the client sends the message, the server receives it and the program ends by itself.

I tried to use a while loop, but then it gives me an Error on binding. Is there any way to make it infinite, so that when user enters exit or some specific key/command, the program ends.

server.c UPDATED with WHILE LOOP

#include<stdio.h>  
#include<stdlib.h>  
#include<sys/types.h>     
#include<sys/socket.h>  
#include<netinet/in.h>  
#include<string.h>  

int main(int argc, char *argv[])  
{  
      int sockfd, newsockfd, portNum, clien, n;
      char buffer[256];
      struct sockaddr_in serv_addr,cli_addr;
  if (argc < 2)
  {
        fprintf(stderr, "\nno port provided");
        exit(1);
  }

  sockfd = socket(AF_INET,SOCK_STREAM, 0);
  if (sockfd < 0)
        printf("\nprovide a valid port number\n");

  bzero((char *)&serv_addr, sizeof(serv_addr));
  portNum = atoi(argv[1]);

  serv_addr.sin_family = AF_INET;
  serv_addr.sin_addr.s_addr = INADDR_ANY;
  serv_addr.sin_port = htons(portNum);

  if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0 )
        printf("error on binding");

  while(1)
  {
       listen(sockfd,5);
  }
  clien = sizeof(cli_addr);
  newsockfd=accept(sockfd, (struct sockaddr *) &cli_addr, &clien );

  if (newsockfd < 0)
        printf("=> Error on accepting...\n");

  bzero(buffer, 256);  
  n = read(newsockfd, buffer, 256); 

  if (n < 0)  
        printf("error reading from socket...\n");

  printf("%s\n", buffer);
  n = write(newsockfd, "message received.", 58);

  if (n < 0)
        printf("cannot write from socket...\n");

  return 0;
}

client.c UPDATED with WHILE LOOP

#include<stdio.h>  
#include<stdlib.h>  
#include<sys/types.h>     
#include<sys/socket.h>  
#include<netinet/in.h>  
#include<netdb.h>  
#include<string.h>  

int main(int argc, char *argv[])  
{  
      int sockfd,portno,n;
      char buffer[256];
      struct sockaddr_in serv_addr;
      struct hostent *server;

      //while(counter != 5)
      // /{
            if (argc < 3)
      {  
            fprintf(stderr,"Usage %s hostname port...\n",argv[0]);
            exit(1);
      }

      portno = atoi(argv[2]);
      sockfd = socket(AF_INET, SOCK_STREAM, 0);
      if (sockfd < 0)
            printf("\error opening socket...\n");

      bzero((char *) &serv_addr, sizeof(serv_addr));
      server = gethostbyname(argv[1]);

      if (server == NULL)
      {
            fprintf(stderr,"no such host...\n");
            exit(0);
      }

      serv_addr.sin_family = AF_INET;
      bcopy((char *)server->h_addr,(char *)&serv_addr.sin_addr.s_addr,server->h_length);
      serv_addr.sin_port = htons(portno);

      if (connect(sockfd, &serv_addr,sizeof(serv_addr)) <0 )  
            printf("\error connecting\n");

      printf("your message:");
      fgets(buffer, 256, stdin);
      while(1)
      {
            n = write(sockfd,buffer,strlen(buffer));
      }
      if (n < 0)
            printf("error writing to socket\n");

      n = read(sockfd, buffer, 255);

      if (n < 0)
            printf("error reading from socket\n");

      printf("%s\n", buffer);          

      return 0;
}

Thank you.

Best Answer

The problem with your server is that you immediately terminate whenever you receive a message. What you should do is keep on listening with the recv() function until the client disconnects. Here is one piece of code that should do the trick.

Disclaimer: However I haven't tested it, it's from an old project that I modified for you on the fly it's supposed to work but I'm not 100% sure it does, I have no time to test it right now but feel free to ask questions if there is something wrong, I'll try to correct it.

EDIT: trying to re-bing causes an error because the binding is already done and the port is already busy so you cannot "assign" an other program to this port therefore giving you an error. The only thing that you have to do is make sure that your server listens until the client disconnects from the server.

Also, it is possible that some of the code was made for c++ at some point, but the networking part should work just fine.

Feel free to try it out and comment if you have questions. Server.c:

    int socket_desc , client_sock , c , *new_sock;
    struct sockaddr_in server , client;

    socket_desc = socket(AF_INET , SOCK_STREAM , 0);
    if (socket_desc == -1)
    {
        //HANDLE ERROR
    }
    printf("Socket created\n");

    //Prepare the sockaddr_in structure
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons( 8000 );

    //Binding, you already do it correctly.
    if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server))< 0)
    {
        //ERROR
    }
    printf("bind done");

    //Listen
    listen(socket_desc , 3);

    printf("Waiting for incoming connections...");
    c = sizeof(struct sockaddr_in);


    while( (client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c)) )
    {
        puts("Connection accepted");

        pthread_t sniffer_thread;
        new_sock = (int*) malloc(1);
        *new_sock = client_sock;

        if( pthread_create( &sniffer_thread , NULL ,  connection_handler , (void*) new_sock) < 0)
        {
            //ERROR
        }

        printf("Handler assigned");
    }

    if (client_sock < 0)
    {
        //ERROR
    }

    //return 0;

}

/*
 * This will handle connection for each client you may have and read indefinitely
 * */
void *connection_handler(void *socket_desc)
{
    //Get the socket descriptor
    int sock = *(int*)socket_desc;
    int read_size;
    char *message , client_message[2000];
    string smatrix ;
    int ind ;
    string tok ;
    int i = 0 ;


    //Receive a message from client
    while( (read_size = recv(sock , client_message , 2000 , 0)) > 0 )
    {
        //What you want to do with the client's message
    }

    if(read_size == 0)
    {
        printf("Client disconnected");
        fflush(stdout);
    }
    else if(read_size == -1)
    {
        //ERROR
    }

    //Free the socket pointer
    free(socket_desc);

As for the client, do a while loop until a certain time has passed or a given character or value is entered. Something like:

while(wantToExit == false){
   char a;
   printf("Please enter a char");
   scanf("%c", &a);
   write(sock , a , 1); //Note use strlen() for strings
}

Hope it helps

Related Topic