NickS
NickS

Reputation: 84

Server proceeding without waiting to read client command in C socket programming

I have a simple server and client written in C.

They communicate well until the very end of my program where the server seems to skip the "read" method and just proceeds, it'll print out a blank line at

 printf("%s", playAgain);

Here is the end of the code

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

#define BACKLOG 10

char invalidPortNumber[] = "Please specify a port number between 2000 and 65535";

char intro[] = "Welcome to the prisoners dilemma";
char playGame[] = "Will you stay silent or betray the other prisoner?\nType S for silent or B for betray";
char option1[] = "The other prisoner betrayed you\nYou each get 2 years in prison";
char option2[] = "The other prisioner betrayed you\nYou get 3 years in prison, the other prisioner is set free";
char option3[] = "The other prisioner stayed silent\nYou are set free, the other prisioner gets 3 years in prison";
char option4[] = "The other prisioner stayed silent\nYou both get 1 year on a lesser charge";

int main(int argc, char *argv[]) {

     if (argc < 2) {
         printf("Run with port number as the argument\n");
         exit(1);
     }
     int port = atoi(argv[1]);
     if (port<2000 || port>65535){
         printf("%s\n", invalidPortNumber);
         exit(2);
     }

    //Struct to store information for IPv4 address
    struct sockaddr_in serverAddress;

    //Create socket for IPv4, reliable stream (TCP), default protocol
    int serverSocket = socket(PF_INET, SOCK_STREAM, 0);

    //Specify that IPv4 family addresses will be used
    serverAddress.sin_family = AF_INET;
    //Set the port number
    serverAddress.sin_port = htons(port);
    //Bind to all local interfaces for IP
    serverAddress.sin_addr.s_addr = INADDR_ANY;

    //Bind the created socket to the IP address specified in the sockaddr_in struct
    bind(serverSocket, (struct sockaddr *) &serverAddress, sizeof(serverAddress));

    //Listen for connections, allowing backlog of up to BACKLOG connection requests
    listen(serverSocket, BACKLOG);
    int play = 0;
    while(1) {

        //Struct to store info of connecting clients
        struct sockaddr_in clientAddress;
        socklen_t clientAddrSize = sizeof(clientAddress);

        //Create a socket for the connection between the client and server
        int connectionSocket = accept(serverSocket, (struct sockaddr *) &clientAddress, &clientAddrSize);
        //Input buffer to store client's request
        do{
        char input[800];
        memset(input, '\0', sizeof(input));

        //Have intro to the game
        write(connectionSocket, intro, sizeof(intro) - 1);

        //Read client's input


        read(connectionSocket, input, sizeof(input)-1);
        if(strcmp(input,"Y\n")==0||strcmp(input,"y\n")==0){
            write(connectionSocket, playGame, sizeof(playGame) - 1);
        }
        else if(strcmp(input,"N\n")==0||strcmp(input,"n\n")==0){
            write(connectionSocket, "Okay, connection closed", sizeof("Okay, connection closed") - 1);
            close(connectionSocket);
            return 0;
        }

        //read clients choice
        char clientChoice[2];
        read(connectionSocket, clientChoice, sizeof(clientChoice)-1);


        srand(time(NULL));
        int random = rand();
        if( random % 2 ==0 ){

            char serverChoice[2] = "S";
            if(strcmp(clientChoice, "S")==0){
                write(connectionSocket, option4, sizeof(option4) - 1);
            }
            else if(strcmp(clientChoice, "B")==0){
                write(connectionSocket, option3, sizeof(option3) - 1);
            }

        }
        else {

            char serverChoice[2] = "B";
            if(strcmp(clientChoice, "S")==0){
                write(connectionSocket, option2, sizeof(option2) - 1);
            }
            else if(strcmp(clientChoice, "B")==0){
                write(connectionSocket, option1, sizeof(option1) - 1);
            }

        }


        char playAgain[5];
        read(connectionSocket, playAgain, sizeof(playAgain)-1);
        printf("%s",playAgain);
        if(strcmp(playAgain, "Play")==0){
            printf("Playing again");
            play=1;
        }
        }while(play==1);
    }

    //Close the server socket and terminate the program if the loop ever ends
    close(serverSocket);
    return 0;

}

That is the server.

And now here is the end of the Client

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

#define BACKLOG 10

char invalidPortNumber[] = "Please specify a port number between 2000 and 65535";

char intro[] = "Welcome to the prisoners dilemma";


int main(int argc, char *argv[]) {
    char buffer[512];
    char IPAddress[15];
    int n;
     if (argc < 2) {
         printf("Run with host IP and port number as the argument\n");
         exit(1);
     }
     int port = atoi(argv[1]);
     if (port<2000 || port>65535){
         printf("%s\n", invalidPortNumber);
         exit(2);
     }

    //Struct to store information for IPv4 address
    struct sockaddr_in serverAddress;

    //Create socket for IPv4, reliable stream (TCP), default protocol
    int serverSocket = socket(PF_INET, SOCK_STREAM, 0);

    //Specify that IPv4 family addresses will be used
    serverAddress.sin_family = AF_INET;
    //Set the port number
    serverAddress.sin_port = htons(port);
    //Bind to all local interfaces for IP
    serverAddress.sin_addr.s_addr = inet_addr("127.0.0.1");

    //Bind the created socket to the IP address specified in the sockaddr_in struct
    int play=0;

    if(connect(serverSocket, (struct sockaddr *) &serverAddress, sizeof(serverAddress))<0){
        printf("Couldn't connect, make sure the server is running and port number is correct \n");
        return 1;
    }
    //read intro from server

    do{
    bzero(buffer,512);
    n = read(serverSocket,buffer,511);
    printf("%s\n",buffer);
    //ask user if they'd like to play
    int validCommand=1;
    do{
    printf("Would you like to play? (Y/N) ");
    bzero(buffer,512);
    fgets(buffer,511,stdin);
    if(strcmp(buffer, "Y\n")==0||strcmp(buffer, "N\n")==0){
        validCommand=0;
    }
    else{
        printf("Invalid command \n");
    }
    }while(validCommand==1);
    //write whether user wants to play to server
    n = write(serverSocket,buffer,strlen(buffer));
    if (n < 0) 
         error("ERROR writing to socket");
    bzero(buffer,512);
    //read response from server
    n = read(serverSocket,buffer,511);
    if (n < 0) 
         error("ERROR reading from socket");
    printf("%s\n",buffer);
    if(strcmp(buffer, "Okay, connection closed")==0){
        close(serverSocket);
        return 0;
    }



    do{
    bzero(buffer,512);
    printf("Make your choice (B/S) ");
    fgets(buffer,511,stdin);
    if(strcmp(buffer, "B\n")==0||strcmp(buffer, "S\n")==0){
        validCommand=0;
    }
    else{
        printf("Invalid command \n");
        validCommand=1;
    }
    }while(validCommand==1);
    //write the users choice to the server
    n = write(serverSocket,buffer,strlen(buffer));
    if (n < 0) 
         error("ERROR writing to socket");
    bzero(buffer,512);
    n = read(serverSocket,buffer,511);
    if (n < 0) 
         error("ERROR reading from socket");
    printf("%s\n",buffer);

    do{
    bzero(buffer,512);
    printf("Would you like to play again? (Play/Quit) ");
    fgets(buffer,511,stdin);
    if(strcmp(buffer, "Play\n")==0||strcmp(buffer, "Quit\n")==0){
        validCommand=0;
    }
    else{
        printf("Invalid command \n");
        validCommand=1;
    }
    }while(validCommand==1);
    //write the users choice to the server
    if(strcmp(buffer, "Quit\n")==0){
        printf("Closing Connection to server");
        close(serverSocket);
        return 0;
    }
    if(strcmp(buffer, "Play\n")==0){
        printf("Playing again");
        play=1;
        n = write(serverSocket,buffer,strlen(buffer)-1);
        if (n < 0) 
         error("ERROR writing to socket");
    }



    }while(play==1);


}

Both the client and server work for the Choice B/S, the client sends, and the server responds. I have no idea what could be wrong, but the server seems to not wait for the clients final command

Upvotes: 0

Views: 934

Answers (1)

Hello World
Hello World

Reputation: 305

First, I think the basic problem you're running into is the common misconception that 1 write corresponds to 1 read automagically. It doesn't.

The problem you mention is caused by your reads and writes being out of sync. You need to make sure that you are reading the same amount as you send each time. The server isn't "proceeding without waiting to read client command;" it has just already read and ignored it.

For instance, when the client does

write(serverSocket, buffer, strlen(buffer))

the server is going to be confused. If you don't send over the size of the string first, the server can't know when to stop reading. This is especially true since you don't send the NUL-terminator. This specific problem could be avoided by doing more processing on the client side. By checking the input against "Y" and "N" on the client, you can simplify the communication to simply sending over a one byte boolean value. This reduces the complexity of your code and the amount of communication required between server and client. If you would like examples of how you might start improving this, or have questions, just ask in the comments.

Side notes:
1) You don't need to send the intro over the socket; it's already on the client side.
2) Boolean variables like validCommand are conventionally 0 for false and 1 for true. You seem to have this flipped in your code. It's not wrong per se, just confusing to read.

Upvotes: 1

Related Questions