Reputation: 84
I have a simple server and client written in C.
They communicate well until the very end of my program where the server seems to skip the "read" method and just proceeds, it'll print out a blank line at
printf("%s", playAgain);
Here is the end of the code
#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;
}
That is the server.
And now here is the end of the Client
#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);
}
Both the client and server work for the Choice B/S, the client sends, and the server responds. I have no idea what could be wrong, but the server seems to not wait for the clients final command
Upvotes: 0
Views: 934
Reputation: 305
First, I think the basic problem you're running into is the common misconception that 1 write corresponds to 1 read automagically. It doesn't.
The problem you mention is caused by your reads and writes being out of sync. You need to make sure that you are reading the same amount as you send each time. The server isn't "proceeding without waiting to read client command;" it has just already read and ignored it.
For instance, when the client does
write(serverSocket, buffer, strlen(buffer))
the server is going to be confused. If you don't send over the size of the string first, the server can't know when to stop reading. This is especially true since you don't send the NUL-terminator. This specific problem could be avoided by doing more processing on the client side. By checking the input against "Y"
and "N"
on the client, you can simplify the communication to simply sending over a one byte boolean value. This reduces the complexity of your code and the amount of communication required between server and client.
If you would like examples of how you might start improving this, or have questions, just ask in the comments.
Side notes:
1) You don't need to send the intro over the socket; it's already on the client side.
2) Boolean variables like validCommand
are conventionally 0
for false and 1
for true. You seem to have this flipped in your code. It's not wrong per se, just confusing to read.
Upvotes: 1