服务器在不等待读取C套接字编程中的客户端命令的情况下继续



我有一个用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 younYou each get 2 years in prison";
char option2[] = "The other prisioner betrayed younYou get 3 years in prison, the other prisioner is set free";
char option3[] = "The other prisioner stayed silentnYou are set free, the other prisioner gets 3 years in prison";
char option4[] = "The other prisioner stayed silentnYou both get 1 year on a lesser charge";
int main(int argc, char *argv[]) {
if (argc < 2) {
printf("Run with port number as the argumentn");
exit(1);
}
int port = atoi(argv[1]);
if (port<2000 || port>65535){
printf("%sn", 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, '', 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,"Yn")==0||strcmp(input,"yn")==0){
write(connectionSocket, playGame, sizeof(playGame) - 1);
}
else if(strcmp(input,"Nn")==0||strcmp(input,"nn")==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 argumentn");
exit(1);
}
int port = atoi(argv[1]);
if (port<2000 || port>65535){
printf("%sn", 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("%sn",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, "Yn")==0||strcmp(buffer, "Nn")==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("%sn",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, "Bn")==0||strcmp(buffer, "Sn")==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("%sn",buffer);
do{
bzero(buffer,512);
printf("Would you like to play again? (Play/Quit) ");
fgets(buffer,511,stdin);
if(strcmp(buffer, "Playn")==0||strcmp(buffer, "Quitn")==0){
validCommand=0;
}
else{
printf("Invalid command n");
validCommand=1;
}
}while(validCommand==1);
//write the users choice to the server
if(strcmp(buffer, "Quitn")==0){
printf("Closing Connection to server");
close(serverSocket);
return 0;
}
if(strcmp(buffer, "Playn")==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这样的布尔变量通常是0表示假,1表示真。你的代码中似乎有这个问题。它本身并没有错,只是读起来令人困惑。

最新更新