Search code examples
csocketstcptcpserver

TCP Echo Server with multiple processes in C


I am trying to write a TCP echo server which creates for each connection a new proccess. But somehow it doesn't work as intended.

    #include <stdlib.h>      // use common functions
#include <stdio.h>       // use input/output functions
#include <string.h>      // use string functions
#include <unistd.h>      // use POSIX functions

#include <sys/socket.h>  // use socket function
#include <netinet/in.h>  // use internet address datatypes
#include <arpa/inet.h>   // use inet_ntoa function

/** A simple server application in the internet domain using TCP.
    The port number is passed as an argument to the program.
*/

#include <netdb.h>
#include <sys/wait.h>

void doprocessing (int sock);

int main( int argc, char *argv[] ) {
   int sockfd, newsockfd, clilen, status;
   struct sockaddr_in serv_addr, cli_addr;
   int pid;
   
   // Read parameters
    if (argc < 2) {
        printf("Usage: TPCServer <port>\n");
        return -1;
    }
    
    int port = atoi(argv[1]);
   
   /* First call to socket() function */
   sockfd = socket(AF_INET, SOCK_STREAM, 0);
   
   if (sockfd < 0) {
      perror("ERROR opening socket");
      exit(1);
   }
   
   /* Initialize socket structure */
   bzero((char *) &serv_addr, sizeof(serv_addr));
   
   serv_addr.sin_family = AF_INET;
   serv_addr.sin_addr.s_addr = INADDR_ANY;
   serv_addr.sin_port = htons(port);
   
   /* Now bind the host address using bind() call.*/
   if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
      perror("ERROR on binding");
      exit(1);
   }
   
   /* Now start listening for the clients, here
      * process will go in sleep mode and will wait
      * for the incoming connection
   */
   
   listen(sockfd,5);
   clilen = sizeof(cli_addr);
   
   while (newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, (socklen_t *) &clilen)) {
        
      if (newsockfd < 0) {
         perror("ERROR on accept");
         exit(1);
      }
      
      /* Create child process */
      pid = fork();
        
      if (pid < 0) {
         perror("ERROR on fork");
         exit(1);
      }
      
      if (pid == 0) {
         char buffer[256];
          
         /* This is the client process */
         close(sockfd);
         
         while(recv(newsockfd, buffer, 100, 0)>0){
            int n;
            
            
            bzero(buffer,256);
            n = read(newsockfd,buffer,255);
   
            if (n < 0) {
                perror("ERROR reading from socket");
                exit(1);
            }
   
            printf("%s\n",buffer);
            n = write(newsockfd,buffer,18);
   
            if (n < 0) {
                perror("ERROR writing to socket");
                exit(1);
            }
            //newsockfd = accept(newsockfd, (struct sockaddr *) &cli_addr, (socklen_t *) &clilen);
         }
         exit(0);
      }
      else {
         /* This is the parent process */ 
         close(newsockfd);
         waitpid(pid, &status, WNOHANG);
      }
        
   } /* end of while */
}

I am getting "bar���������������" when I should get "foo42bar". I think the problem is keeping the connecting alive. So I expect the bug somewhere here:

if (pid == 0) {
         char buffer[256];

         /* This is the client process */
         close(sockfd);

         while(recv(newsockfd, buffer, 100, 0)>0){
            int n;


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

            if (n < 0) {
                perror("ERROR reading from socket");
                exit(1);
            }

            printf("%s\n",buffer);
            n = write(newsockfd,buffer,18);

            if (n < 0) {
                perror("ERROR writing to socket");
                exit(1);
            }
            //newsockfd = accept(newsockfd, (struct sockaddr *) &cli_addr, (socklen_t *) &clilen);
         }
         exit(0);
      }

Thanks for your help.


Solution

  • You have two issues:

    After n = read(newsockfd,buffer,255);, the variable n holds the number of bytes read. That's the number of bytes you should print and the number of bytes you should write. But in your subsequent print and send code, you don't use the value of n, so you send or print more characters than you received, resulting in the junk you see.

    Your print may work by luck since you zero the buffer. Though that will fail if the received data happens to contain a zero byte. But the call to write always sends 18 bytes, which could be too many or too few.

    Also, for some reason you call recv in the while loop and throw the result away. That will cause data loss. Don't call recv then read. Pick one to use and don't throw the result away since that's the data you want to echo.