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.