服务器在 C 套接字编程中无需等待读取客户端命令即可继续

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

我有一个用 C 语言编写的简单服务器和客户端。

他们沟通良好,直到我程序的最后,服务器似乎跳过 "read" 方法并继续进行,它会在

处打印出一个空行
 printf("%s", playAgain);

代码到此结束

#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, '[=11=]', 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;

}

那是服务器。

客户端到此结束

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


}

客户端和服务器都为Choice工作B/S,客户端发送,服务器响应。我不知道出了什么问题,但服务器似乎不等待客户端的最终命令

首先,我认为您遇到的基本问题 运行 是一种常见的误解,即 1 次写入对应于 1 次自动读取。它没有。

您提到的问题是您的读写不同步导致的。您需要确保每次读取的数量与发送的数量相同。服务器不是 "proceeding without waiting to read client command;" 它刚刚已经读取并忽略了它。

例如,当客户端

write(serverSocket, buffer, strlen(buffer))

服务器将会混乱。如果您不首先发送超过字符串的大小,服务器将不知道何时停止读取。尤其如此,因为您不发送 NUL 终止符。通过在客户端进行更多处理可以避免这个特定问题。通过检查客户端上 "Y""N" 的输入,您可以将通信简化为简单地发送一个字节的布尔值。这降低了代码的复杂性以及服务器和客户端之间所需的通信量。 如果您想了解如何开始改进它的示例,或者有任何疑问,请在评论中提问。

旁注:
1)您不需要通过套接字发送介绍;它已经在客户端。
2) 像 validCommand 这样的布尔变量通常是 0 表示假,1 表示真。您似乎在代码中翻转了这一点。本身并没有错,只是读起来很混乱。