C server weird behavior - c

So, I have this piece of code, which will just read the message from the client and reply with a "yup"
while(strcmp(buffer, "QUIT") != 0){
bzero(buffer, 255); //cleans the read buffer
/*this reads the aux (request) from the client*/
recv(newsockfd, buffer, 255, 0);
if(strlen(buffer))
printf("Thread %d: %s\n", thread_no, buffer);
fflush(stdout);
write(newsockfd, "yup\n", 4);
}
The problem is that at the very first reading everything goes ok, but all other readings are messed up, if I send the message "guitar", for example, it gets the 'g', loops and then it gets the "uitar", sending aother "yup".
I have no clue what's happening.

Long story short: TCP isn't a message orientated protocol, it's a stream orientated protocol. Messages might be fragmented or merged together, and your application has to deal with that (the only guarantee is that you'll receive the data in the same order you sent it in).

recv() reads as many data as are available currently. You should read until you hit EOF, an error or a newline. Only if you have that newline, you have a complete line which you then compare with "QUIT", and which youi acknowledge with "Yup."

Three other bugs in the code snippit above.
1) Not checking the return value from recv(). The socket could have been closed gracefully (return value == 0), suffered an error (return value == -1), etc... More importantly, there's not to suggest that you will receive all 4 bytes of the "QUIT" message that was sent by a remote send call. You may only receive "Q".
2) If recv() were to receive 255 characters (none of which being a null char), then the subsequent strlen() will read into invalid memory and possibly crash.
3) Not checking the return value of the write call.

Related

No code runs after a read or a write in socket programming in c [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
I am making a server client program in c.
The server starts first waits for the client then the client "connects".
after the client connects it waits for input from the user while the server is running read() to get that input from the client.
Here is the main issue.
after a new line character has been discovered by the while loop it then sends this data in the buffer from the client to the server which is waiting with a read. The server reads but no code below the read can be run unless it has something to do with the buffer.
so if the code is like this
read(socket_fd, buff, sizeof(buff));
printf("data from the client: %s", buff); // this line will be run in the terminal
printf("TESTING TESTING TESTING"); // this line will never be read
same thing on the clients side.
after it performs the write() on the client side any code that is under the write will not be ran. basically making this essentially a deadlock where both programs (I think) are just waiting on input from the other.
I don't know why this is. perhaps it is waiting for more data with the read, but that wouldn't explain why it runs code that prints the buffer but not anything else.
here is the snippet that sends and recieves data from the client side. The server is set up with TCP
while(1){
//wait for data from user
bzero(buffer, 256);
printf("Enter the string : ");
n = 0;
while ((buffer[n++] = getchar()) != '\n')
;
write(sockfd, buffer, sizeof(buffer));
printf("WE HERE");
read(sockfd, buffer, sizeof(buffer));
printf("READING THE DATA");
printf("From Server : %s", buffer);
if ((strncmp(buffer, "exit", 4)) == 0) {
printf("Client Exit...\n");
break;
}
}
and here is the server code which reads the data from the client and provides a response.
while(1) {
bzero(buffer, 256);
//read the message from the client
read(newsockfd, buffer, sizeof(buffer));
printf("From the client: %s", buffer);
printf("WORKING HERE BEFORE LOWER CASE [SERVER]");
printf("the buffer again: %s", buffer);
lower_string(buffer);
printf("WORKING AFTER THE LOWER CASE [SERVER]");
write(sockfd, buffer, sizeof(buffer));
printf("WRITING TO THE CLIENT");
if (strncmp("exit", buffer, 4) == 0) {
printf("Server Exit...\n");
break;
}
bzero(buffer, 256);
}
Your code contains a number of problems:
You aren't putting newline characters at the end of your printf() statements, which means that the printed text won't be visible until the stdout buffer gets full enough to force it to be flushed to the console. That is probably confusing you about the behavior of your program, since printf() statements are being executed but you aren't seeing their output in a timely manner. You should do e.g. printf("WE HERE\n"); rather than printf("WE HERE");
You aren't capturing the return values from send() and recv() into a variable so that you can examine what values they returned and act on them appropriately. If you don't look at the return values, you don't know how many bytes were actually sent or received (it may be less than the number of bytes you asked to be sent or received!) and you don't know if there was an error or an EOF condition that occurred.
You should be aware that recv() will block until at least one byte of data is available to place into your passed-in buffer, and similarly, write() can block until at least one byte of your passed-in buffer can be consumed by the networking stack. This can indeed lead to a deadlock in certain circumstances (e.g. if the remote peer never sends any data because it is blocked inside a recv() waiting for you to send some data to it first). This problem can be handled via various more advanced techniques (e.g. timeouts, or non-blocking or asynchronous I/O) but I won't go into those here.
Zeroing out your entire 256-byte array and then receiving up to 256 bytes means that in the case where you received 256 bytes of data at once, your array will not be NUL-terminated, and you will invoke undefined behavior if you try to use it as a C-string (e.g. by passing it to printf("%s", buffer);. You'd be better off receiving sizeof(buf)-1 bytes instead (and if you capture the return value of recv() as suggested in point #2, you can then just set buffer[numBytesReceived] = '\0'; afterwards, which is a more efficient way to make sure the string is NUL-terminated than unnecessarily clearing out all 256 bytes)
Note that you cannot assume that you will recv() the entire string within a single recv() call. It's unlikely to happen in this toy program (unless your network conditions are very bad), but in general it's possible for the sender to send() e.g. "123456789" and the receiver's first recv() call to get "1234" and then the second recv() call gets "567" and then the third gets "89", or any other combination of subsets of the string. The receiver is guaranteed to receive all of the bytes in order, but not guaranteed to receive them all at once. Production-level code would need to be smart enough to handle that correctly.

How to handle blocking read() call when reading from a socket?

I'm writing a simple IRC client program in C for self-teaching purposes, and am having trouble understanding the behavior of the read() function when called reading from a socket file descriptor.
The following code snippet works and prints the same output as running
$ echo "NICK gertrudes\r\nUSER a 0 * d\r\n" | nc chat.freenode.net 6667
in the terminal, which is the same as my program prints so far:
while ((n = read(sockfd, buffer, sizeof(buffer)-1)) > 0) {
printf("\nloop\n");
buffer[n] = '\0';
if (fputs(buffer, stdout) == EOF)
error("fputs");
}
if (n < 0)
error("reading from socket");
printf("out of the loop\n");
What I fail to understand is why the program never gets to the final printf call, and rather sits there as if waiting for more from the server. Does that mean that the last reply was longer than 0 and the IRC server just won't send anything new until I send another command?
If so (at the risk of going off-topic here), and read() is blocking, where would I write the logic of sending commands to the server while the program is waiting for that call to return?
What I fail to understand is why the program never gets to the final printf call, and rather sits there as if waiting for more from the server.
It is waitng for more from the server. read() will return zero when the peer disconnects, and not before.
Despite your program not being complete, there are several things that you are wrongly assuming. Let's comment these in your code.
while ((n = read(sockfd, buffer, sizeof(buffer)-1)) > 0) {
It's good to read sizeof(buffer)-1 if you plan to complete it with a \0 byte, but think that you can receive a \0 from the socket, if you want to be general, don't assume you are always reading text. Many security exploits come from errors like this. The programmer assumes (erroneously) that the data is ascii text, and someone exploits a buffer overrun (this is not the case) or something illegal, feeding a lot of null characters to make it fail.
printf("\nloop\n");
buffer[n] = '\0';
if (fputs(buffer, stdout) == EOF)
This is a VERY common mistake... you are used to see that when you put a \n at the end of a buffer, stdio prints everything until the last buffer as soon as it sees it. Well, for this to happen, stdio checks if the descriptor is associated to a terminal (by means of an ioctl(2) call, or a call to isatty(3)). This is no longer true with sockets, so probably your buffer has been copied to stdio buffer, and stdio is waiting for the buffer to fill or you to explicitly flush the buffer with fflush(3) before calling write(2) to send all the data over it.
error("fputs");
Do a fflush(stdout); at this point, so you are sure all your data is sent to the peer, before continuing, or don't use stdio at all (use simple write(2) calls, until you are proficient enough to prepare a thread that select(2)s on the socket to feed more data as soon as it is ready to accept more data)
}
if (n < 0)
error("reading from socket");
printf("out of the loop\n");

String comparison after transfer through TCP socket in C

I am sending a file through TCP, and have the server sending a message containing "END_OF_MESSAGE" to alert the client that they have received the whole file and can close the socket. The file is being sent, and the client receives the "END_OF_MESSAGE" string, however, when I use strcmp to compare the received information to "END_OF_MESSAGE", it never says that they match. I have tried strncmp and memcmp but am confused as to why strcmp does not tell me the strings match.
Code snippets:
Server:
char endMessage[MESSAGESIZE] = "END_OF_MESSAGE";
if ((send(clntSocket, endMessage, sizeof endMessage, 0))!= sizeof endMessage) DieWithError("Sending failed");
The above code snippet does get sent.
Client:
if ((bytesRcvd = recv(sock, echoBuffer, RCVBUFSIZE - 1, 0)) <= 0)
DieWithError("recv() failed or connection closed prematurely");
totalBytesRcvd += bytesRcvd; /* Keep tally of total bytes */
echoBuffer[bytesRcvd] = '\0'; /* Terminate the string! */
if (!(strcmp(echoBuffer, "END_OF_MESSAGE")==0)){
printf(echoBuffer); /* Print the echo buffer */
printf("\n");
}else{
break; //break out of while loop
}
the strcmp of the echoBuffer and "END_OF_MESSAGE" never returns 0, even though "END_OF_MESSAGE" is what I am sending from the server..I have tried strncmp to compare the first 3 characters ("END") to no avail.
Note: when I print out the echoBuffer, the very last one does print out END_OF_MESSAGE which is just adding to my confusion.
Does anyone have any insights into what I am doing wrong?
Thank you.
am sending a file through TCP, and have the server sending a message containing "END_OF_MESSAGE" to alert the client that they have received the whole file and can close the socket.
Why? Just close the socket. That will tell the client exactly the same thing..
What you're attempting is fraught with difficulty. What happens if the file contains END_OF_MESSAGE? You're going to need an escape convention, and an escape for the escape, and inspect all the data when both sending and receiving.
The actual problem that you're seeing is that END_OF_MESSAGE can arrive along with the last bit of the file, so it isn't at the start of the buffer.
But it's all pointless. Just close the socket.

How to send and receive newline character over sockets in a client server model?

I am trying to learn client server model in Linux and I have setup two C files namely server.c and client.c. These are the code snippets that I seem to have problems with.
server.c code snippet
char* message = "<query>\n";
write(client_socket_filedescriptor, message, sizeof(message));
client.c code snippet
char* message = "<query>\n";
read(socket_filedescriptor, buffer, sizeof(buffer));
printf("%s", buffer);
printf("\n\n");
printf("%s", message);
Now when I run my server and then when I run my client, I expect the printf statements to print the same strings that is <query>\n, but I keep getting different outputs for buffer and message variables.
The output looks a bit like this when I run client code.
Output image
As you see, these two strings are different. I am trying to simulate a typical TCP handshake and I want to make sure that these two strings are same and then client will start writing or doing something with that server. But I am having this trivial problem. Could anyone tell my how to resolve it? I plan to use strcmp to compare buffer and message variables, but as it stands now, strcmp doesn't return 0 since these are different strings afterall.
You are ignoring the count returned by read(). It can be -1, indicating an error, or zero, indicating end of stream, or a positive number, indicating how many bytes were received. You cannot assume that read() fills the buffer, or that a single send() or write() corresponds to a single recv() or read().
In detail:
write(client_socket_filedescriptor, message, sizeof(message));
You are only sending four bytes, the size of the pointer. And you're ignoring the return value. It should be
int count = write(client_socket_filedescriptor, message, strlen(message));
if (count == -1)
perror("write"); // or better
char* message = "<query>\n";
read(socket_filedescriptor, buffer, sizeof(buffer));
That should be
int count = read(socket_filedescriptor, buffer, sizeof(buffer));
if (count == -1)
perror("read"); // or better
else if (count == 0)
; // end of stream: the peer has disconnected: close the socket and stop reading
else
Back to your code:
printf("%s", buffer);
That should be
printf("%.*s", count, buffer);
I plan to use strcmp()
You should plan to use strncmp(), with count above as the length parameter. In any case you can't assume the input ends with a null unless you (a) ensure you send the null, which you aren't, and (b) write a read loop that stops when you've read it.

Sending data to and from using sockets in c

I am working on an program for school and having some issues with sockets. I have pasted the write and read commands from my program below since I think these are the problem. The program should take the plaintext file and encrypt it using the key provided.
MY PROBLEM: When I execute the program using "client [plaintext] [key] [port]" the program returns "Reading data from client -- 140 bytes" and then just hangs. I can hit ctrl-c and the program prints the correct output for ptext and ktext and that 37 bytes were sent back to the client (which is the correct number of bytes). I feel like the encrypted text should print as well but it does not.
TWO QUESTIONS:
1) Why does the program hang?
2) Why does it seem like data is written from the server to the client but the client does not read any of the data?
Thank you in advance for any help you can offer.
CLIENT
n = write(sockfd,ptext,strlen(ptext));
bzero(crypt_text, BUF_MAX);
bzero(buffer, BUF_MAX);
while((n = read(sockfd,buffer,BUF_MAX))>0){
printf("Reading data from Server -- %d bytes\n",n);
strcat(crypt_text, buffer);
bzero(buffer,BUF_MAX);
}
if (n < 0){
error("ERROR reading from socket");
}
printf("%s", crypt_text);
SERVER
while((n = read(newsockfd,buffer,512))>0){
printf("Reading data from client -- %d bytes\n",n);
strcat(full_text, buffer);
bzero(buffer,BUF_MAX);
}
if (n < 0){
error("ERROR reading from socket");
}
bzero (ptext,BUF_MAX);
bzero (ktext, BUF_MAX);
strcpy(ptext, strtok(full_text,"["));
strcpy(ktext, strtok(NULL, "["));
printf("ptext length ==%s %d\n\n",ptext,strlen(ptext)); //Prints the correct plain text
printf("ktext length ==%s %d\n\n",ktext,strlen(ktext)); //prints the correct key
crypt_text = encrypt(ptext, ktext);
n = write(newsockfd,crypt_text,strlen(crypt_text));
printf("WRITE TO CILENT ==== %d",n); //This returns the correct number of bytes that should be sent back to client
if (n < 0){
error("ERROR writing to socket");
}
As is, your client and server will always hang waiting for each other. This is because read() blocks by default until new data is available to fetch from the file (in this case, a socket).
Look carefully at the code:
The client writes once into the socket before entering the read loop
The server only reads from the socket (well, further down there is a write(), but it will never reach it). The first time the loop runs on the server, it will read the data that the client initially wrote into the socket.
The server processes the data it just read and concatenates it to full_text. Then it goes back to the loop condition, where it calls read() again. read() blocks because there is nothing else to read from the socket at this point.
The client enters a similar loop where it attempts to read from the socket, expecting messages from the server.
At this point, both the server and the client are blocked waiting for messages from each other, which will never happen.
Tu put it another way: you only wrote to the socket once, and somehow you expect to read it multiple times.
You have to rethink your design. Go back to the problem description, work your way through a simple protocol, dry run it on paper, and then implement it - that's how it's done in the real world :)
There are other bugs in your code. For example you write this:
strcat(full_text, buffer);
But buffer is not NUL terminated. n bytes have been read, the rest of the buffer is indeterminate. You should set a '\0' byte at offset n and only try reading BUF_MAX-1 bytes to keep a byte available for all cases and do this:
buffer[n] = '\0';
strcat(full_text, buffer);
Furthermore, you do not test if there is enough room available in full_text for the n+1 bytes strcat will copy at the end.
On another front, packets can be sliced and diced into chunked of different sizes when received by the server. Buffering is required to ensure a reliable client / server communication. To enable this buffering, you need to devise a protocol to determine when a packet has been fully received: a simple protocol is to transmit lines terminated by '\n'.

Resources