0

I am relatively new to socket programming so kindly please bear with me.

I am trying to make a simple guessing integer game using socket programming that has specific protocols (delimiters, "H", "L", "O").

I am not sure why the client resend a raw blank data, when the client user has not inputted any guess integer at all.

Below are parts of the server.c file:

#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 <time.h> /* time for randomizer*/ 


void error(const char *msg)
{
    perror(msg);
    exit(1);
}

int main(int argc, char *argv[])
{
    int sockfd, newsockfd, portno, n;
    socklen_t clilen;
    char buffer[256];
    struct sockaddr_in serv_addr, cli_addr;

    int GuessedInteger, integerRandom, serverFlagCorrect;
    char charGuess[4], answerServer[1];
    char* delimiter = "\\n";

    /** initialization of variables **/
    serverFlagCorrect = 0;

    /** generate random integer from 1 to 100 **/
    srand (time(NULL));
    integerRandom = (rand() % 100) + 1;

    printf("This is the random integer : %d \n", integerRandom);   

    if (argc < 2) {
        fprintf(stderr,"ERROR, no port provided\n");
        exit(1);
    }

    // Creates the socket socket() --> endpoints of sockets
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) 
       error("ERROR opening socket");
    // Creates the socket socket() --> endpoints of sockets

    // assign unique new address
    bzero((char *) &serv_addr, sizeof(serv_addr));
    portno = atoi(argv[1]);
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(portno);

    if (bind(sockfd, (struct sockaddr *) &serv_addr,
             sizeof(serv_addr)) < 0) 
             error("ERROR on binding");
    // assign unique new address

    // wait for a connection
    listen(sockfd,1);
    // wait for a connection

    // accepts the connection
    clilen = sizeof(cli_addr);
    newsockfd = accept(sockfd, 
                (struct sockaddr *) &cli_addr, 
                &clilen);
    if (newsockfd < 0) 
         error("ERROR on accept");
    // accepts the connection

    while (serverFlagCorrect != 1) 
    {

        // reads the data being received
        bzero(buffer,256);
        n = read(newsockfd,buffer,255);
        if (n < 0) error("ERROR reading from socket");
        // reads the data being received

        printf("Buffer from client: <%s>\n", buffer);
        memcpy(charGuess, buffer, sizeof(charGuess));
        printf("Message from client in charGuess: <%s>\n", charGuess);

        /* Put if statement here for error out if no \n at the end */
        int len = strlen(charGuess);
        const char *last_two = &charGuess[len-2];

        printf("Last two characters of charGuess: <%s>\n", last_two);

        if (strncmp ( last_two, delimiter, 2) )
            error (" ERROR Wrong protocol received");

        /** process the string to integer for server comparison **/
        GuessedInteger = atoi(charGuess);
        printf("Guessed Integer : %d \n", GuessedInteger);

        /** Server response for comparison**/
        if (GuessedInteger > integerRandom)
            memcpy(&answerServer, "L", sizeof(answerServer));
        else if (GuessedInteger < integerRandom)
            memcpy(&answerServer, "H", sizeof(answerServer));
        else if (GuessedInteger == integerRandom)
            {
                serverFlagCorrect = 1;
                memcpy(&answerServer, "O", sizeof(answerServer));
            }
        printf("Value of answerServer: %c\n", *answerServer);
        /** Server response for comparison**/

        // sends the answer
        n = write(newsockfd, answerServer, 1);
        if (newsockfd < 0) 
            error("ERROR on accept");
        // sends the answer

        // closes what was sent
        close(newsockfd);
        // closes what was sent

    }        

    //closes the socket if random integer was found
    close(sockfd);

    return 0; 
}

And below is the client.c file:

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

void error(const char *msg)
{
    perror(msg);
    exit(0);
}

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

    int integerGuess, clientFlagCorrect;
    int numberOfTries;
    char charGuess[1024], answerServer[1];
    char* delimiter = "\\n";


    if (argc < 3) {
       fprintf(stderr,"usage %s hostname port\n", argv[0]);
       exit(0);
    }
    portno = atoi(argv[2]);

    // Creates the socket socket() --> endpoints of sockets
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) 
        error("ERROR opening socket");
    // Creates the socket socket() --> endpoints of sockets

    server = gethostbyname(argv[1]);
    if (server == NULL) {
        fprintf(stderr,"ERROR, no such host\n");
        exit(0);
    }

    // connects to the service in connect()
    bzero((char *) &serv_addr, sizeof(serv_addr));
    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,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) 
        error("ERROR connecting");
    // connects to the service


    /** initialization of variables **/
    clientFlagCorrect = 0;
    numberOfTries = 0;

    while (clientFlagCorrect != 1) 
    {
        numberOfTries = numberOfTries + 1;

        /** initialization of variables **/
        integerGuess = 0;
        memset(charGuess, 0, sizeof(charGuess));

        // ask the user for the guessed number
        printf("Guess: ");
        bzero(buffer,sizeof(buffer));
        fgets(buffer,sizeof(buffer)-1,stdin);
        printf("Buffer to be processed : <%s>\n", buffer);
        // ask the user for the guessed number

        /** process the integer to string and add a delimiter **/
        integerGuess = atoi(buffer);
        printf("integerGuess : <%d> \n", integerGuess);
        sprintf( charGuess, "%d", integerGuess);    
        strcat( charGuess, delimiter);
        printf("String Guess : <%s> \n", charGuess);

        memset(buffer,0,sizeof(buffer));
        memcpy(buffer, charGuess, sizeof(charGuess));
        printf("Buffer to send : <%s>\n",buffer);
        /** process the integer to string and add a delimiter **/

        // send the string that was processed
        n = write(sockfd,buffer,strlen(buffer));
        if (n < 0) 
             error("ERROR writing to socket");
        // send the string that was processed

        // reads the data being received
        bzero(buffer,256);
        n = read(sockfd,buffer,255);
        if (n < 0) 
             error("ERROR reading from socket");
        // reads the data being received

        printf("Buffer received : <%s>\n",buffer);

        memcpy(&answerServer, buffer, sizeof(answerServer));
        printf ("Value of answerServer : <%c> \n", *answerServer);

        /** Client response **/
        if (strncmp ( & answerServer[0],"L",sizeof(answerServer)) == 0)
            printf("Lower \n");
        else if (strncmp ( & answerServer[0],"H",sizeof(answerServer)) == 0)
            printf("Higher \n");
        else if (strncmp ( & answerServer[0],"O",sizeof(answerServer)) == 0)
            {
                printf("Correct \n");
                clientFlagCorrect = 1;
            }
        else
            error("ERROR Wrong message received");

    }

    printf ("Tries: %d \n", numberOfTries);

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

    close(sockfd);
    return 0;
}

Any advice in fixing this rather annoying bug that I have been trying to fix for half a day?

Thought I mention (if it matters), I am not going to use fork here yet. I will also do something similar that has fork functions after I pulled this simple guessing game without using fork first.

EDIT1: Added what I get via terminal (and sorry, I don't think it's good that I remove some parts of the code of the server and client):

Server terminal:

$ gcc -Wall -o server server.c
$ ./server 5678
This is the random integer : 66 
Buffer from client: <20\n>
Message from client in charGuess: <20\n>
Last two characters of charGuess: <\n>
Guessed Integer : 20 
Value of answerServer: H
ERROR reading from socket: Bad file descriptor
$ 

Client terminal:

$ ./client3 localhost 5678
Guess: 20
Buffer to be processed : <20
>
integerGuess : <20> 
String Guess : <20\n> 
Buffer to send : <20\n>
Buffer received : <H>
Value of answerServer : <H> 
Higher 
Guess:   

I've checked that it has been sending from client when the user from the client has not been sending anything yet.

3
  • Code this long is definitely too localized for SO. (Read the FAQ for types of questions to ask and not to ask here) Commented Mar 18, 2013 at 14:50
  • @lc., lemme try to snip things up to the parts where I'm facing the problem. And might as well add in the results I get via terminal. Commented Mar 18, 2013 at 14:59
  • @lc.- I did not clipped some codes above but just added what I am getting in my terminal windows. Hope that make things clearer what I am getting. Commented Mar 18, 2013 at 15:07

1 Answer 1

2

The printf debugging output already gives an indication what went wrong. Taking a look at the last line reported from the server you'll stumble across:

ERROR reading from socket: Bad file descriptor

This problem arises from trying to read from an already closed file descriptor. To somewhat lighten the code jungle of your example I just copied the relevant parts. Hopefully this way the mistake will be easier to spot:

while (serverFlagCorrect != 1) 
{
    // ...

    /* reads pretty well in the first run */
    n = read(newsockfd,buffer,255);

    // ...

    close(newsockfd);
    /* oops - there won't be any filedescriptor to read from in the second run */
}
/* close() should be placed here instead */

While everything is fine on the first run just after entering the loop newsockfd will not be a valid file descriptor any more after you closed it. Moving the close (newsockfd) line to the spot indicated should solve the issue.

2
  • Oh. I see now. The close should be outside the while loop. Thanks! Commented Mar 18, 2013 at 22:27
  • I actually thought that every time the read() runs, it will wake up since it is still in the listening state. I guess, I understood wrong. Thanks again! Commented Mar 18, 2013 at 22:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.