Sending data to and from using sockets in c - 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'.

Related

Reading from Socket in a loop?

I am creating a server/client TCP in C.
The idea is for the server to send a relatively large amount of information. However, the buffer in the client has a size of only 512 (I don't want to increase this size), and obviously, the information sent by the server is larger than this. Let's imagine 812 bytes.
What I want to do is, in the client, read 512 bytes, print them on the client's console, and then read the remaining bytes, and print them as well.
Here's what should happen:
1) Create server, and block in the read() system call (waiting for the client to write something);
2) Create the client, and write something in the socket, and then blocks on read(), waiting for the server to respond;
3) The server's read() call returns, and now server has to send that large amount of data, using the following code (after creating a new process):
dup2(new_socketfd, STDOUT_FILENO); // Redirect to socket
execlp("/application", "application", NULL); // Application that prints the information to send to the client
Let's imagine "application" printed 812 bytes of data to the socket.
4) Now the client has to read 812 bytes, with a buffer size of 512. That's my problem.
How can I approach this problem? I was wondering if I could make a loop, and read until there's nothing to read, 512 by 512 bytes. But as soon as there's nothing to read, client will block on read().
Any ideas?
recv will block when there is no data in the stream. Any data extracted from the stream, the length is returned from recv.
You can write a simple function to extract the full data just by using an offset variable and checking the return value.
A simple function like this will do.
ssize_t readfull(int descriptor,char* buffer, ssize_t sizetoread){
ssize_t offset = 0;
while (offset <sizetoread) {
ssize_t read = recv(descriptor,buffer+offset,sizetoread-offset,0);
if(read < 1){
return offset;
}
offset+=read;
}
return offset;
}
Also servers typically send some kind of EOF when the data is finished. Either the server might first send the length of the message to be read which is a constant size either four or eight bytes, then it sends the data so you know ahead of time how much to read. Or, in the case of HTTP for example, there is the content-length field as well as the '\r\n' delimeters.
Realistically there is no way to know how much data the server has available to send you, it's impractical. The server has to tell you how much data there is through some kind of indicator.
Since you're writing the server yourself, you can first send a four byte message which can be an int value of how much data the client should read.
So your server can look like this:
int sizetosend = arbitrarysize;
send(descriptor,(char*)&sizetosend,sizeof(int),0);
send(descriptor,buffer,sizetosend,0);
Then on your client side, read four bytes then the buffer.
int sizetoread = 0;
ssize_t read = recv(descriptor,(char*)&sizetoread,sizeof(int),0);
if(read < 4)
return;
//Now just follow the code I posted above

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");

Server TCP stuck on read()

I'm trying to get a server to receive messages from a client in TCP.
The problem is, I only receive the messages on the server side once I close the socket on the client side.
Here is the read function on the server side:
char *read_socket(int fd){
int bytesRcvd, aux;
char *buffer=(char*)malloc(BUFFSIZE*sizeof(char));
bytesRcvd=read(fd, buffer , BUFFSIZE);
aux=bytesRcvd;
while(bytesRcvd>0){
if((bytesRcvd = read(fd, &buffer[aux], BUFFSIZE))<0){
printf("read() failed!: %s\n", strerror(errno));
exit(1);
}
aux+=bytesRcvd;
}
return &buffer[0];
}
I know (by printfs) that it gets stuck on the line:
bytesRcvd = read(fd, &buffer[aux], BUFFSIZE)
Any help will be greatly appreciated.
Your program is reading the data in the line:
bytesRcvd = read(fd, &buffer[aux], BUFFSIZE)
Your while loop receives the data that the client sends. If the client doesn't have data to send read will block until the connection is closed where read will return 0 and you will exit from while loop.
This is the reason that you think that the data are send in the end (when connection is closed). This is not right, if you print the data you read in the while loop you will see them immediately and not all of them in the end.
Though you can't return the data before the connection is closed due to read() blocking.
For one client your program may seems ok if you don't have the problem of getting data at the end (as I said you could just print them inside while loop) but imagine have two or more clients then you would firstly close connection with first client to go on and read data from second and so on.
One solution(to both problems) is to use select() system call, this will go on to read only if there are data.( Though select() is not safe when using fork()- doesn't guarantee that a parent of child process will not block in read() ).

Redirecting stdout to socket in client-server situation

I'm new to this forum, so I'm sorry if my question is not correctly asked. I'll try to be as clear as possible.
I'm trying to code two programs (client.c and server.c, using TCP sockets) in Linux, with the following behavior:
Client sends messages to Server that contain commands (ls, mkdir, etc) to be run by Server.
Server runs these commands, and sends program output (stdout) back to Client.
Client prints the recieved program output.
So far, I have this:
server.c:
/*After creating socket with socket(), binding to address and port,
putting in listening mode and accepting connection*/
dup2(sock_client,1); //redirect stdout
while(1){
recv(sock_client,buf,MAX_MSG_LENGTH,0);
/*If the message recieved was END_STRING, exit this loop*/
if (strncmp(buf, END_STRING, MAX_MSG_LENGTH) == 0)
break;
system(buf);
}
client.c:
/*After creating socket and connecting*/
while(fgets(buf,MAX_MSG_LENGTH,stdin)){
send(sock,buf,MAX_MSG_LENGTH,0);
if (!strncmp(buf,END_STRING,MAX_MSG_LENGTH)){
/*If the message recieved was END_STRING, exit this loop*/
break;
}
read(sock,buf,MAX_MSG_LENGTH); //read stdout from program
printf("%s\n",buf);
}
My problem is that, if a command has a long output, there's some "garbage" left from it when showing the output of the next commands, so I was wondering if there was a way to flush the socket (apparently not, based on my google research), or maybe to accomplish the expected server-client behavior in some other way.
Thank you!
EDIT:
Ok, I've finished the client. Here's the code:
client.c:
/* After creating socket and connecting*/
while(fgets(buf,MAX_MSG_LENGTH,stdin)){
send(sock,buf,MAX_MSG_LENGTH,0);
if (!strncmp(buf,END_STRING,MAX_MSG_LENGTH)){
/*If the message recieved was END_STRING, exit this loop*/
break;
}
while(1){
read_size = read(sock,buf,MAX_MSG_LENGTH);
/*Print read_size characters from buf*/
printf("%.*s\n", read_size, buf);
if (read_size < MAX_MSG_LENGTH){
/*Keep on reading until read_size < MAX_MSG_LENGTH, then exit this loop*/
break;
}
}
/*Clear buffer, just in case*/
for (i = 0; i < MAX_MSG_LENGTH; i++){
buf[i] = 0;
}
Just as a comment, this program will not work properly if the command sent to the server doesn't have any standard output (for example, mkdir new_directory), since, in this case, read() will leave the client permanently blocked, causing the server to never recieve the next command to be run or the END_STRING message to leave the program from the client. You could probably fix this by using a non-blocking socket and using select() to read from socket, just like synther suggested. Additionally, in the server, after the system(buf); line, you should add fflush(0), which will flush all the buffers (including the socket, which could be useful if the command send by the client has a really short output).
Thanks a lot!
Thank you for your answers!
I tried adding this to my client.c code:
/*After creating socket and connecting*/
while(fgets(buf,MAX_MSG_LENGTH,stdin)){
/*Send command to server*/
send(sock,buf,MAX_MSG_LENGTH,0);
if (!strncmp(buf,END_STRING,MAX_MSG_LENGTH)){
/*If the message recieved was END_STRING, exit this loop*/
break;
}
while(1){
read_size = read(sock,buf,MAX_MSG_LENGTH); //read stdout from program
printf("%.*s\n", read_size, buf);
if (read_size < MAX_MSG_LENGTH){
/*Exit this loop when reading less that MAX_MSG_LENGTH*/
break;
}
}
/*Clear the 'buf' array. I don't know if this is really necessary*/
for (i = 0; i < MAX_MSG_LENGTH; i++){
buf[i] = 0;
}
}
And now, after every command, the client only prints the output of the last command sent. I will test it more thoroughly and edit my original post if this solution is correct, so thanks a lot!
Perhaps, you get "garbage" in client when your command's output exceeds MAX_MSG_LENGTH. read(sock,buf,MAX_MSG_LENGTH); reads just MAX_MSG_LENGTH bytes from socket, remaining chars in socket are read the next time when you except it from the next command.
You can fix it in multiple ways in client.
read returns the actual number of bytes read. You can compare it with MAX_MSG_LENGTH and decide to read one more time or not. But if your actual data is exactly MAX_MSG_LENGTH bytes then you decide to read again and read blocks waiting data that is not available at the moment (and stdin blocks too, user can't send new command).
Use non-blocking socket to fix issue in 1. read will return immediately when no available data.
Add end-of-command marker to your server's output and client will know when to stop reading and switch to stdin reading.
Use select() mechanism to read from socket and user input "simultaneously". It allows to read from multiple file descriptors (socket and stdio) when data available on any of them.
Additionally, you use the same buffer for user commands and server responses. Typically, user commands are shorter then server output and buf could contain parts of last server outputs. Then you send this mix of user command and last server output to server.
And, as stated above, read returns the actual number of bytes read. You should print the exactly received number of bytes from buf, not all the data.
int ret = read(sock,buf,MAX_MSG_LENGTH); //read stdout from program
printf("%.*s\n", ret, buf);

Resources