Search code examples
csocketstcpclient-server

C TCP/IP Sockets: How to synchronise input from client sockets to a server socket to be alternating


I have a program that ultimately I want to make into a tic-tac-toe client-server game, but I am currently just testing the communication with sending and printing messages. I am okay up to the point of the server receiving messages from multiple clients, but the whole thing fails when I try to force it to alternate between clients, as in take input from client 1, then client 2, then 1 again etc. I am sure I am just going about it in a very wrong way.

Here is the code forming the connections and communicating with the clients.

listen(sockfd,5);
clilen = sizeof(cli_addr);


//client1
clientsockfd[0] = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (clientsockfd[0] < 0) {
  perror("ERROR on accept");
  exit(1);
}

//client2
clientsockfd[1] = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (clientsockfd[1] < 0) {
  perror("ERROR on accept");
  exit(1);
}

while (1) {

  //create child process for each client
  pid1 = fork();
  if (pid1 < 0) {
     perror("ERROR on fork");
     exit(1);
  }

  //client1
  if (pid1 == 0) {
     /* This is the client process */
     close(sockfd);
     doprocessing(clientsockfd[i]);

  }
  //client2
  if(pid2 == 0){
      close(sockfd);
      doprocessing(clientsockfd[i]);
      //functions
  }

  i++;

}

I also tried forking for the second time inside the first fork but it also failed.

Here is the part of client.c concerning the communication with the server.

 if (connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
   perror("Error connecting: ");
   exit(1);
}

while(1){

      //ask for message to be read by server
      printf("Please enter the message: ");
      bzero(buffer,256);
      fgets(buffer,255,stdin);

      // send message
      n = write(sockfd, buffer, strlen(buffer));

      if (n < 0) {
         perror("Error writing to socket: ");
         exit(1);
      }

      //empty buffer
      bzero(buffer,256);

      //read reply from server
      n = read(sockfd, buffer, 255);
      if (n < 0) {
         perror("Error reading from socket: ");
         exit(1);
      }

      printf("%s\n",buffer);
}
return 0;
}

Also here is the doprocessing function in case it is necessary

void doprocessing (int sock) {
int n;
char buffer[256];
bzero(buffer,256);
n = read(sock,buffer,255);

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

printf("Here is the message: %s\n",buffer);
n = write(sock,"I got your message",18);

if (n < 0) {
  perror("ERROR writing to socket");
  exit(1);
}

}

What I get when running the program is: Upon the connection of the second client, there is an endless loop, where:

ERROR reading from socket: Bad file descriptor

is repeated many times, then:

ERROR on fork: recourse temporarily unavailable

appears twice, and finally:

ERROR reading from socket:Input/output error

is repeated endlessly till I force-terminate the program. If I have omitted any info necessary, please let me know and I will add it. Thanks.


Solution

  •     while (1) {
            pid = fork();
            ....
            i++;
        }
    

    creates too many child processes, eventually causing failure to fork.

    Each child uses clientsockfd[i]; only two of them are actually allocated. Meanwhile i grows towards infinity; the third process already gets a garbage socket (it is also an out-of-bound access, therefore UB), which explains IO errors.

    Consider instead forking the clients once, and

        while (1) {
           doprocessing(clientsockfd[0]);
           doprocessing(clientsockfd[1]);
        }
    

    in the mainline.