Reputation: 23
So I am having a weird problem that I have been facing in my program that is basically a client/server socket programming example in C. I have taken time away from the problem, but I cannot seem to locate what is causing the problem.
If needed, I can post more details, but following is what is not working.
while(1)
{
char word[256];
gets(word);
printf("%s",word);
if(strcmp(word, "TRANSLATE") == 0 || strcmp(word, "GET") == 0 ||strcmp(word, "STORE") == 0 || strcmp(word, "EXIT") == 0)
{
if(strcmp(word, "TRANSLATE") == 0)
{
if(send(sock , word , strlen(word) , 0)<0)
{
printf("Send Error\n");
return 1;
}
bzero(server_reply,2000);
if(recv(sock , server_reply , 2000 , 0)<0)
{
puts("Recieving Error\n");
}
//Print out 200ok message
printf("%s\n", server_reply);
//Get the first word
gets(word2);
while(strcmp(word2,"." )!= 0)
{
if(send(sock , word2 , strlen(word2) , 0)<0)
{
printf("Send Error\n");
return 1;
}
gets(word2);
}
if(recv(sock , server_reply , 2000 , 0)<0)
{
puts("Recieving Error\n");
}
printf("%s\n", server_reply);
//STILL NEED TO WORK ON PARSING OUT SPACES BECAUSE RESULT IS IN A STRING, JUST WITH SPACES.
//ALSO NEED TO DO SERVER SIDE CAPITALIZATION
}
if(strcmp(word, "GET") == 0)
{
printf("Getting");
/*
if(send(sock , word , strlen(word) , 0)<0)
{
printf("Send Error\n");
return 1;
}
bzero(server_reply,2000);
if(recv(sock , server_reply , 2000 , 0)<0)
{
puts("Recieving Error\n");
}
//Print out 200ok message
printf("%s\n", server_reply);
/*
if(recv(sock , server_reply , 2000 , 0)<0)
{
puts("Recieving Error\n");
}
//Print out the KANSAS message
printf("%s\n", server_reply);
*/
}
}
The code breaks once I uncomment in the "GET" selection, and it doesn't even hit the printf() statement before the if statement.If I leave it out it hits all the proper statements perfectly. Am I missing something? Also, I am thinking it may be something with the server communication, so this is the server code.
#include<stdio.h>
#include<string.h> //strlen
#include<sys/socket.h>
#include<arpa/inet.h> //inet_addr
#include<unistd.h> //write
int main(int argc , char *argv[])
{
int socket_desc , client_sock , c , read_size;
struct sockaddr_in server , client;
char client_message[2000];
//Create socket
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
if (socket_desc == -1)
{
printf("Could not create socket");
}
puts("Socket created");
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 5149 );
//Bind
if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
{
//print the error message
printf("bind failed. Error");
return 1;
}
puts("bind done");
//Listen
listen(socket_desc , 3);
//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);
//accept connection from an incoming client
client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c);
if (client_sock < 0)
{
printf("accept failed");
return 1;
}
puts("Connection accepted");
//Receive a message from client
while( (read_size = recv(client_sock , client_message , 2000 , 0)) > 0 )
{
if(strcmp(client_message,"TRANSLATE")==0)
{
*(client_message + read_size) = '\0';
char word[256]="200 OK TRANSLATE";
write(client_sock, word, strlen(word));
/*
while( (read_size = recv(client_sock , client_message , 2000 , 0)) > 0 )
{
*(client_message + read_size) = '\0';
puts(client_message);
write(client_sock,client_message,strlen(client_message));
if(strcmp(client_message,".")==0)
{
printf("breaking");
break;
}
printf("IN while loop");
}
printf("Out of while loop");
*/
}
if(strcmp(client_message,"GET")==0)
{
*(client_message + read_size) = '\0';
char word[256]="200 OK GET";
write(client_sock, word , strlen(word));
char word2[256]="I don't think we're in Kansas anymore.";
write(client_sock, word2 , strlen(word2));
}
if(strcmp(client_message,"STORE")==0)
{
char word[256]="200 OK STORE";
write(client_sock, word , strlen(word));
}
}
if(read_size == 0)
{
puts("Client disconnected");
fflush(stdout);
}
else if(read_size == -1)
{
printf("recv failed");
}
return 0;
}
Upvotes: 0
Views: 359
Reputation: 1
You should add a \n
at end of every printf
format control string and/or call fflush(3)
The main issue in your program is the wrong belief that a given send
(or write
) to a socket(7) corresponds to a single recv
(or read
) on the other side.
A tcp(7) implementation is just a stream of bytes ; there is no implicit message boundaries. So your application should buffer and explicitly split that stream into meaningful messages.
It could happen, and it does happen, that one side is able to send
or write
4000 bytes at once followed by another emission of 1000 bytes, but the other side would first recv
(or read
) e.g. 39 bytes, then 1 byte, then 1960 bytes then 3000 bytes. You then understand that "messages" are not intact, there is only a stream of bytes.
An additional difficulty is that such behavior is not reproducible. The next time you'll run your server and client programs they will behave differently!
In practice, it is helpful to define well where are the message boundaries. You could do like in HTTP, i.e. put some content length (in HTTP, the Content-Length:
attribute in reply headers) in the beginning of each message. You could also decide that a message is a single long line with a single newline terminating it (and then, you could need a convention to escape internal newlines), look e.g. at JSON. And of course you should buffer on both sides.
You might want to test the readability or writability of a socket (or a pipe) with a multiplexing call like poll(2) (perhaps in your event loop)
I strongly suggest to read Advanced Linux Programming and some Linux Socket Tutorial.
BTW, always test your syscalls for failure. See intro(2) and use perror(3) or errno(3) (often with strerror(3)).
Of course compile with all warnings and debug info (gcc -Wall -g
) and use the debugger (gdb
) (and perhaps also strace(1)). You might want to debug with two gdb
sessions (one for the server, one for the client) in different terminals.
BTW, don't use the obsolete deprecated bzero
function, use the standard memset(3) instead.
Upvotes: 3