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。在我没有先使用 fork 拉出这个简单的猜谜游戏之后,我也会做一些类似的具有 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 回答