簡體   English   中英

服務器在 C 套接字編程中無需等待讀取客戶端命令即可繼續進行

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

我有一個用 C 編寫的簡單服務器和客戶端。

他們溝通良好,直到我的程序結束,服務器似乎跳過“讀取”方法並繼續進行,它會在

 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, '\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;

}

那就是服務器。

現在這是客戶端的結尾

#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 次讀取。 它沒有。

你提到的問題是你的讀寫不同步造成的。 您需要確保每次讀取的數量與發送的數量相同。 服務器不是“在不等待讀取客戶端命令的情況下繼續進行”; 它剛剛閱讀並忽略了它。

例如,當客戶端執行

write(serverSocket, buffer, strlen(buffer))

服務器會感到困惑。 如果您不先發送超過字符串的大小,服務器將無法知道何時停止讀取。 這尤其正確,因為您不發送 NUL 終止符。 通過在客戶端進行更多處理可以避免這個特定問題。 通過檢查客戶端上的"Y""N"輸入,您可以將通信簡化為簡單地發送一個字節的布爾值。 這降低了代碼的復雜性以及服務器和客戶端之間所需的通信量。 如果您想了解如何開始改進這一點的示例,或者有疑問,請在評論中提問。

旁注:
1)您不需要通過套接字發送介紹; 它已經在客戶端。
2)像validCommand這樣的布爾變量validCommand0表示假, 1表示真。 你似乎在你的代碼中翻轉了這個。 這本身並沒有錯,只是讀起來令人困惑。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM