0

私はソケットプログラミングに比較的慣れていないので、ご容赦ください。

特定のプロトコル (区切り文字、「H」、「L」、「O」) を持つソケットプログラミングを使用して、単純な推測整数ゲームを作成しようとしています。

クライアントユーザーが推測整数をまったく入力していないのに、クライアントが生の空白データを再送信する理由がわかりません。

以下は、server.c ファイルの一部です。

#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; 
}

以下は client.c ファイルです。

#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;
}

私が半日修正しようとしてきたこのかなり厄介なバグを修正するためのアドバイスはありますか?

(重要な場合) 言及したと思いますが、ここではまだ fork を使用しません。また、最初にフォークを使用せずにこの単純な推測ゲームをプルした後、フォーク機能を備えた同様のことを行います。

EDIT1:ターミナル経由で取得したものを追加しました(申し訳ありませんが、サーバーとクライアントのコードの一部を削除するのは良くないと思います):

サーバー端末:

$ 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
$ 

クライアント端末:

$ ./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:   

クライアントからのユーザーがまだ何も送信していないときに、クライアントから送信されていることを確認しました。

4

1 に答える 1

2

printf のデバッグ出力には、何が問題なのかが既に示されています。サーバーから報告された最後の行を見ると、次のようになります。

ERROR reading from socket: Bad file descriptor

この問題は、既に閉じられているファイル記述子から読み取ろうとした場合に発生します。あなたの例のコードジャングルをいくらか軽くするために、関連する部分をコピーしました。うまくいけば、この方法で間違いを見つけやすくなります。

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 */

ループに入った直後の最初の実行ではすべて問題ありnewsockfdませんが、ループを閉じた後は有効なファイル記述子ではなくなります。close (newsockfd)示された場所に線を移動すると、問題が解決するはずです。

于 2013-03-18T16:38:10.117 に答える