Server TCP stuck on read() - c

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() ).

Related

One socket descriptor always blocked on write. Select not working?

Hello I have a server program and a client program. The server program is working fine, as in I can telnet to the server and I can read and write in any order (like a chat room) without any issue. However I am now working on my client program and when I use 'select' and check if the socket descriptor is set to read or write, it always goes to write and then is blocked. As in messages do not get through until the client sends some data.
How can I fix this on my client end so I can read and write in any order?
while (quit != 1)
{
FD_ZERO(&read_fds);
FD_ZERO(&write_fds);
FD_SET(client_fd, &read_fds);
FD_SET(client_fd, &write_fds);
if (select(client_fd+1, &read_fds, &write_fds, NULL, NULL) == -1)
{
perror("Error on Select");
exit(2);
}
if (FD_ISSET(client_fd, &read_fds))
{
char newBuffer[100] = {'\0'};
int bytesRead = read(client_fd, &newBuffer, sizeof(newBuffer));
printf("%s",newBuffer);
}
if(FD_ISSET(client_fd, &write_fds))
{
quit = transmit(handle, buffer, client_fd);
}
}
Here is code to transmit function
int transmit(char* handle, char* buffer, int client_fd)
{
int n;
printf("%s", handle);
fgets(buffer, 500, stdin);
if (!strchr(buffer, '\n'))
{
while (fgetc(stdin) != '\n');
}
if (strcmp (buffer, "\\quit\n") == 0)
{
close(client_fd);
return 1;
}
n = write(client_fd, buffer, strlen(buffer));
if (n < 0)
{
error("ERROR writing to socket");
}
memset(buffer, 0, 501);
}
I think you are misinterpreting the use of the writefds parameer of select(): only set the bit when you want to write data to the socket. In other words, if there is no data, do not set the bit.
Setting the bit will check if there is room for writing, and if yes, the bit will remain on. Assuming you are not pumping megabytes of data, there will always be room, so right now you will always call transmit() which waits for input from the command line with fgets(), thus blocking the rest of the program. You have to monitor both the client socket and stdin to keep the program running.
So, check for READ action on stdin (use STDIN_FILENO to get the file descriptor for that), READ on client_fd always and just write() your data to the client_fd if the amount of data is small (if you need to write larger data chunks consider non-blocking sockets).
BTW, you forget to return a proper value at the end of transmit().
Sockets are almost always writable, except when the socket send buffer is full, which indicates that you are sending faster than the receiver is receiving.
So your transmit() function will be entered every time around the loop, so it will read some data from stdin, which blocks until you type something, so nothing happens.
You should only select on writability when a prior send() has returned EWOULDBLOCK/EAGAIN. Otherwise you should just send, when you have something to send.
I would throw this code away and use two or three threads in blocking mode.
select is used to check whether a socket has become ready to read or write. If it is blocking for read then that indicates no data to read. If it is blocking in write, then that indicates the TCP buffer is likely full and the remote end has to read some data so that the socket will allow more data to be written. Since the select blocks until one of the socket descriptions is ready, you also need to use timeout in select to avoid waiting for a long time.
In your specific case, if your remote/receiving end keep reading data from the socket then the select will not block for the write on the other end. Otherwise the tcp buffer will become full on the sender side and select will block. Answers posted also indicate the importance of handling EAGAIN or EWOULDBLOCK.
Sample flow:
while(bytesleft > 0)
then
nbytes = write data
if(nbytes > 0)
bytesleft -= nbytes;
else
if write returns with EAGAIN or EWOULDBLOCK
call poll or select to wait for the socket to be come ready
endif
endif
if poll or select times out
then handle the timeout error(e.g. the remote end did not send the
data within expected time interval)
endif
end while
The code also should include handle error conditions and read/write returning with (For example, write/read returning with 0). Also note read/recv returning 0 indicates the remote end closed the socket.

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'.

Knowing when Client has finished reading from the socket in C

I am writing a client-server program in c where I have to send multiple image files from the server to the client. Is there any way for the server to know when the client has finished reading from socket, creating the image file locally, and successfully written to it? P.S. I already tried sending a message to the socket and when I try to read the socket from the server, the program hangs. Any help will be much appreciated.
Here is a function from the Server code which sends the file to socket:
while(1)
{
unsigned char buf[256] = {0};
int n = fread(buf,1,256,fp);
if(n>0) { send(sockfd,buf,n,0); }
if(n<256) {
if(feof(fp))
printf("Sent to socket\n");
break;
}
}
fclose(fp);
}
char buf[5]
read(sockfd,buf,5);
if(strcmp(buf,"ready")==0) //send more files
And here is a function from the client to write to the file:
FILE* fp;
fp = fopen(file_path,"ab");
char buf[256];
int num;
int total=0;
while(( num = recv(sockfd,buf,256,0))>0)
{
total+=num;
fwrite(buf,1,num,fp);
}
fclose(fp);
write(sockfd,"ready",5);
}
When I do a read on the server after one file transfer, the program hangs.
You problem is here in the client:
while(( num = recv(sockfd,buf,256,0))>0)
recv() will only return 0 at end-of-file - ie when the server shuts down the sending side of the socket. However your server isn't doing that - it's waiting for a response from the client. This means you deadlock.
If you want to send multiple images in the one connection, you need to send your client some information to allow it to tell when one image ends. One way to do this is to first send your client the size of the file it should expect, then the file data. The client can then keep track of how many bytes it's recieved, and send the "ready" reponse after that.
You need a kind of protocol to allow :
the server to tell the client that all has been written
the client to tell the server that all has been read
If you only send one file, the simplest way is to use shutdown(sockfd, SHUT_WR) server side after all data has beed sent. That way the client will get a 0 as return from recv signaling end of data and will be able to send its acknowledgement. But you can no longer write on the socket server side.
If you want to be able to send more than one file, you will have to imagine a cleverer protocol. A common one would be to send blocs of data preceded by their size
short sz = htons(n); /* deals with possible endianness problems */
send(sockfd, &sz, sizeof(short), 0)
send(sockfd, buf, n);
And a sz == 0 (with no buf ...) would signal end of data
This would still be a simple protocol with no error recovery, but at least it can work when no incident happens.

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

why the last read() takes a long time to return

I wirte a simple program that use unix sockets to download a html file from a server.
I use a write() to send "Get /index.html Host:*" message,and then use a while loop to read()
response. Everything goes well but the last read() which will return 0 takes a long time to return.Any idea to correct the code so that I need't to wait for this special time? or how can this happened?
sprintf(cmdstr,"%s %s %s\r\nHOST:%s\r\n\r\n",METHOD,place,VERSION,host);
cmdlen = strlen(cmdstr);
if (write(sockfd,cmdstr,cmdlen) != cmdlen) {
perror("write cmd error");
return ;
}
while ((n = read(sockfd,read_data,BUFSIZE)) > 0) {
read_data[n] = 0;
p = read_data;
if (filep == NULL) {
if (filep = fopen(filename,"w")) == NULL) {
perror("fopen ");
return;
}
p = strstr(read_data,"\r\n\r\n");
p += 4;
}
fputs(p,filep);
}
printf ("%s download completed.\n",filename);
If there is no data ready, recv will block or fail (depending on whether it's blocking or non-blocking).
recv returns zero when the other end of the socket has closed the connection. Never otherwise.
This does not normally happen with HTTP/1.1 (almost all existing servers today), at least not immediately, since connections are expected to be keep-alive by default.
Send a Connection: close to signal to the server that you do not want this behaviour. It should then drop the connection ASAP (but after sending you everything, of course).
Alternatively, you can try calling shutdown(sockfd, SHUT_WR);, which performs a half-close of the connection, and which a server might (should, hopefully) react to appropriately.
Or, finally, you can only read as much as the content length tells you and then drop the connection, but that is kind of antisocial towards the server, and not entirely without risk.
Because you are asking the socket to read BUFSIZE data when there is no more to read. I'm assuming that the call to read blocks waiting for more data to come across the TCP connection and will only return when the connection goes down some time later.
If you know how big the file is then you can request that only that amount of data is read. If you don't know how big the file is then you are relying on the server to close the connection when the file has been transferred.

Resources