Hello people,

i'm new here, and i hope that you can give me a hand with a little client-server software that i'm doing that it's driving me nuts.

The essence of the program is very simple, you have this client (in my case cliente.c, as i'm Spanish) with this syntax once compiled:

#./cliente -r remote_file -h ip_address -l local_file

This client sends the name of the remote file to the server, and the server sends the contents of said remote file to the client. The client then stores the information in "local_file". As you can see, it isn't a big deal. We're assuming both files are text files.

So, i'm basically using a write loop to send the data to the client, and a read loop to receive it. And that's where my problem is: The read loop generates an endless loop which causes my computer to freeze.

I've been trying various combinations and loops, to no avail. The only thing obtained was that, in the case that i totally erased the loop leaving just what was inside it, i would receive the info of the first iteration of the server loop, but then it would logically crash.

My question is, how can i manage to make the file transfer well? I'm going totally bananas with this case.

So as not to make this post huge, i'm only copying the interesting part of both the client and server.

Client:

if( connect(sockfd, (struct sockaddr *)&servidor, sizeof(servidor))<0)
    {
      printf("ERROR al conectar \n");
      exit(1);
    }
  write(sockfd, nom_remoto, 16); //nom_remoto contains the name of the remote file

  while(aux=read(sockfd, buffer, 16)!=0){ //buffer[16]
  if(aux==-1){
  printf("Error en el read");
  }

  else	fputs(buffer,fp);//fp=fopen(nom_local,"w");
  
  
  }
  printf("Everything's ok");
  fclose(fp);
  close(sockfd);

Server:

while(1)
    {
      connfd=accept(sockfd,(struct sockaddr *)&cliente,&clilen);
      
      if((pid==fork())==0)
	{
	  close(sockfd);
	  read(connfd, nom_docu,16);
          
	  fp = fopen(nom_docu,"rt");
	  while(fgets(archivo,16,fp)!=NULL){//archivo[16]
	  write(connfd, archivo, 16);
          	
	  }
	close(connfd);
	fclose(fp);
	
	}
      else close(sockfd);
    }

Just in case you're wondering, the rest of both works perfectly, i'm 99% sure that the problem of my software lies here.


Thank you so much for the help.

Recommended Answers

All 24 Replies

In your client, try shutting down the write portion of the client socket after you sent the filename to the server.

Also try downloading wireshark, Its great for debugging client/server programs.

Thank you so much for the help, but, can you explain a bit further what do you mean by "shutting down the write portion"? I think i know, but i just want to confirm.

PS: Ok, i have wireshark installed, i'll check it out.

This client/server program...Windows or Linux?

Linux, i'm running it on ubuntu 9.10 netbook remix

while(aux=read(sockfd, buffer, 16)!=0)

is not doing what you expect it to do. Hint: it assigns aux a result of comparison.

One side point: you should not use fgets and fputs (at least not as careless as you do). read and write are better suited for the task.

Also, n server.c at line 20:

else close(sockfd);

should be

else close(connfd);

Thank you nezachem, i'm going to look into it, and i'll let you guys know the result.

Hello guys, i've figured out a pretty unorthodox way to fix my problem, but for some weird reason, it works.

Client:

if( connect(sockfd, (struct sockaddr *)&servidor, sizeof(servidor))<0)
    {
      printf("ERROR al conectar \n");
      exit(1);
    }
  write(sockfd, nom_remoto, 16);

  while(aux!=0){
  aux=read(sockfd, buffer, 16);
  if(aux==-1){
  printf("Error en el read");
  }

  else if(strcmp(buffer2,buffer)!=0){

	strcpy(buffer2,buffer);
	
  	
	fputs(buffer,fp);
       }
  else break;
  
  
  }
  printf("Transferencia OK \n");
  fclose(fp);
  close(sockfd);

Server

while(1)
    {
      connfd=accept(sockfd,(struct sockaddr *)&cliente,&clilen);
      
      if((pid==fork())==0)
	{
	  close(sockfd);
	  read(connfd, nom_docu,16);
          fp = fopen(nom_docu,"rt");
          while(i!=1){
	  
	  fgets(archivo,16,fp);
          num=sizeof(archivo);
          if(num==0){
          i=1;
          }
          else
          
	  write(connfd, archivo, 16);
          }	
	fclose(fp);  
	close(connfd);
}

My only problem, is that when i execute the client, it gets the job done, but after saying "Transferencia OK", the server for some reason stops its own execution, when in theory it shouldn't happen due to the while(1) loop. Any ideas?

Thank you.

A fairly unorthodox indeed. A standard read/store loop is

while((aux = read(sock, buf, size)) > 0)
    write(out, buf, aux);

Note additional parenthesis in the while condition. Also notice usage of aux in the write call.

Line 13 in the server loop always calculates the same value (either 16 or 4, depending on how archivo is declared), regardless of how many bytes fgets got from the file. The num never becomes 0, with all the consequences. Again, I highly recommend to use read() instead of fgets() .

A fairly unorthodox indeed. A standard read/store loop is

while((aux = read(sock, buf, size)) > 0)
    write(out, buf, aux);

Note additional parenthesis in the while condition. Also notice usage of aux in the write call.

Line 13 in the server loop always calculates the same value (either 16 or 4, depending on how archivo is declared), regardless of how many bytes fgets got from the file. The num never becomes 0, with all the consequences. Again, I highly recommend to use read() instead of fgets() .

The thing is that, this is an exercise for a certain subject at college, and the professor is pretty much encouraging us to use fgets, and fputs. Besides, in my short C experience i've never used read and write to handle FILEs, so even if i wanted to, i would have to do some research.

So, my challenge now is to see how can i stop the while(i!=1) loop after the entire file is read. I've been able to notice that

fgets(archivo,16,fp)!=NULL

was the one that was giving me the endless loop, my professor said earlier that nowadays it wasn't recommended to use that line, and it seems he was right, the compiler understands it, but it totally ruins the socket.

I've been able to notice that

fgets(archivo,16,fp)!=NULL

was the one that was giving me the endless loop, my professor said earlier that nowadays it wasn't recommended to use that line

This is a most surprising claim. Either your professor is incompetent, or you misunderstood him. The fact that it gives you a hard time tells that the problem is somewhere else in the program.

the professor is pretty much encouraging us to use fgets, and fputs

In that case you must realize that there is a trouble waiting to happen. Keep in mind, that a read() from the socket may return less data than requested. In your case, the returned chunk may have neither '\n' nor terminating '\0', so fputs will happily send all the trailing garbage to the file.
To use fputs() you must force a '\0' at the proper place in the buffer.

I understand what you mean. That professor is known here to be pretty controversial, and i can assure you he said that about fgets. Anyways, without abandoning the fgets and fputs, my mission now is to find a stop condition to the loop in the server, and to prevent the incoming garbage to the buffer. Could this be a way to solve the latter?

while(aux!=0){
  aux=read(sockfd, buffer, 16);
  buffer[aux]='\0'; // In this case, buffer would be buffer[17] instead of buffer[16]
  if(aux==-1){
  printf("Error en el read");
  }

  else if(strcmp(buffer2,buffer)!=0){

	strcpy(buffer2,buffer);
	
  	
	fputs(buffer,fp);
       }
  else break;
  
  
  }
  printf("Transferencia OK \n");
  fclose(fp);
  close(sockfd);

I understand what you mean. That professor is known here to be pretty controversial, and i can assure you he said that about fgets. Anyways, without abandoning the fgets and fputs, my mission now is to find a stop condition to the loop in the server, and to prevent the incoming garbage to the buffer. Could this be a way to solve the latter?

while(aux!=0){
  aux=read(sockfd, buffer, 16);

I would prefer

while((aux=read(sockfd, buffer, 16)) > 0)
buffer[aux]='\0'; // In this case, buffer would be buffer[17] instead of buffer[16]

Correct.

if(aux==-1){
  printf("Error en el read");
  }
  else if(strcmp(buffer2,buffer)!=0){
	strcpy(buffer2,buffer);
	fputs(buffer,fp);
   }
    else break;
  }

This is definitely wrong. If the file has 2 identical consecutive strings, you'd terminate transfer prematurely.
You must find the root cause of your original problem. Do not mask it.

I would prefer

while((aux=read(sockfd, buffer, 16)) > 0)

Correct.

This is definitely wrong. If the file has 2 identical consecutive strings, you'd terminate transfer prematurely.
You must find the root cause of your original problem. Do not mask it.

Thank you so much for the effort nezachem, the deadline is May 7th so i definitely have time left, but i think i'm going to get me a 2-3 days break because this program is becoming an obsession and i think i've lost focus, and proof of that is that i'm not able to see where the big problem is yet.

The ultimate mission of the client socket is to execute ssh to provide a ssh tunnel to the file transfer via port forwarding. To do so, we must use fork() and execl. After talking to the teacher the other day, she pretty must said that in order to do so, we must use these lines:

if ((pid = fork()) == 0){
    execl("ssh", "ssh", "-L","3500:localhost:5000" , NULL); 

  } //Considering 3500 is the port of the client and 5000 the port of the server.

However, i've tried that, and while it compiles well, a wireshark capture (via "follow tcp stream" option) shows clearly that the data isn't being sent encrypted, thus meaning that ssh isn't working.
Of course i've checked that the daemon sshd is working on the server, and the AllowTCPForwarding is activated on the sshd_config file.

I'm not asking for help in this case because that might be wearing out my welcome, but i can't figure out why it isn't working.

As i said, in 3 days i'll look into it again with a more relaxed perspective, because right now it's driving me nuts.

Hello again,

after a 3-day break, i've decided to take on the program again. In a more relaxed mood, i've read and checked every single line of both the client and the server, and i've tried to simplify everything as much as possible.

Well, i may be wrong, but i've come to the conclusion that fgets is pretty much ruining the whole concept.

If i execute both systems (on different computers, on the same computer it gives an endless loop), they keep running all the time. That would be cool for the server, because it is supposed to do that, but not so much for the client. If i cancel the server (Ctrl-C), then the execution of the client also stops; it gives the "Transferencia OK" warning, and if you check the local file you can clearly see that everything went well.

So, it seems that the only thing happening here is that this loop:

while((fgets(archivo,16,fp))!=NULL){
	  
	  archivo[16]='\0';
          
	  write(connfd, archivo, strlen(archivo));
          
           }

never stops, and thus the server is unable to close the communication with the client.

You said nezachem that it would be better to use read instead of fgets, and that's my next step, could you please give me the syntax of the function? i've researched on the internet and i've found both the read and write functions inside fcntl.h , but i've found them really confusing.

Here's what i have right now:

Server:

while(1)
    {
      connfd=accept(sockfd,(struct sockaddr *)&cliente,&clilen);
      
      if((pid==fork())==0)
	{
	  close(sockfd);
	  aux=read(connfd, nom_docu,16);
		  nom_docu[aux]='\0';
          fp = fopen(nom_docu,"rt");
          while((fgets(archivo,16,fp))!=NULL){
	  
	  archivo[16]='\0'; //archivo[17]
          
	  write(connfd, archivo, strlen(archivo));
          
           }
    
         fclose(fp);  
	close(connfd);

	
	
	}
      else close(connfd);
    }
  	
}

Client:

if( (connect(sockfd, (struct sockaddr *)&servidor, sizeof(servidor))<0))
    {
      printf("ERROR al conectar \n");
      exit(1);
    }
  write(sockfd, nom_remoto, 16);

  while((aux=read(sockfd, buffer, 16)) > 0){
  buffer[aux]='\0';
  	
	fputs(buffer,fp);
       }
  
  
  
  printf("Transferencia OK \n");
  fclose(fp);
  close(sockfd);

Thank you very much in advance.

I was planning to write a long response. I was planning to write the same client-server pair myself (and I actually did) to prove that there's nothing wrong with the posted code, and that the problem lies somewhere outside of the fragments you presented.
But at the last moment I noticed a little problem, right there in the server fragment.

if((pid==fork())==0)

Highlighted in red.

Obviously, pid (however (un)initialized it is) does not compare equal to the value returned by fork(); the comparison is false, and both parent and child enter the if clause. That explains all the contradictions, weirdnesses, and inconsistencies in your system behaviour.

The most valuable lesson here is that an incomplete code is impossible to debug.
Even more valuable one is that meditative debugging doesn't worth a dam.

PS:

to use read instead of fgets, and that's my next step, could you please give me the syntax of the function

You already have used them to communicate through the socket. Use write(fileno(fp), buffer, aux) at client.c:12 and read(fileno(fp), archivo, 16) at server.c:13

commented: Nice +5

Well, first of all, again,thank you very much for the help, you're basically turning into my hero because i finally think i'm near the finish line.
I fixed the pid==fork thing (pid was declared as pid_t pid by the way) and made a test, aaaaand it works, the client shows the "Transferencia OK" and stops its execution, and on the other hand the server keeps running. My only gripe now is that for some reason, after the first client is served, the server slows down the computer a whole lot,to the point that it basically freezes it (we're talking two separate computers here). So, what i am going to do is to put here the entire code of the server, maybe i should have put it right from the beginning, but i thought it could be a bit of an overkill.

Server:

#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#define PUERTO 5000
#define QUEUE 5

int main(int argc, char *argv[])
{

  int sockfd, connfd;
  struct sockaddr_in cliente,servidor;
  socklen_t clilen;
  pid_t pid;
  char nom_docu[17];
  char archivo[17];
  FILE *fp;
  int aux;


  if((sockfd= socket(AF_INET,SOCK_STREAM,0))<=0){
	printf("ERROR al hacer el socket  \n");
	exit(1);
  }
  bzero(&servidor,sizeof(servidor));
  servidor.sin_family=AF_INET;
  servidor.sin_port=htons(PUERTO);
  if(argc==2){
    servidor.sin_addr.s_addr=inet_addr(argv[1]);
  }
  else
    {
      servidor.sin_addr.s_addr=htonl(INADDR_ANY);
    }
  
  if(bind(sockfd,(struct sockaddr *)&servidor,sizeof(servidor))<0){
	printf("ERROR al hacer bind \n"); exit(1);
  }
  clilen=sizeof(cliente);
  listen(sockfd,QUEUE);

  while(1)
    {
      connfd=accept(sockfd,(struct sockaddr *)&cliente,&clilen);
      
      if((pid=fork())==0)
	{
	  close(sockfd);
	  aux=read(connfd, nom_docu,16);
		  nom_docu[aux]='\0';
          fp = fopen(nom_docu,"rt");
          while((fgets(archivo,16,fp))!=NULL){
	  
	  archivo[16]='\0';
          
	  write(connfd, archivo, strlen(archivo));
          
           }
    
         fclose(fp);  
	close(connfd);

	
	
	}
      else close(connfd);
    }
  	
}

One little comment is that the server is supposed to have 2 options:
1) ./server Ip_address -> This way the server will have the ip_address introduced
2) ./server -> This way the server will automatically search for one (INADDR_ANY)

On line 51 why are you closing the server socket ? Should that not be like the last step of the program ?

Thanks for posting the code. Yet again, as soon as I was able to compile it, run it, and generally play with it, the problem became obvious.

My only gripe now is that for some reason, after the first client is served, the server slows down the computer a whole lot,to the point that it basically freezes it (we're talking two separate computers here).

while(1) {
      connfd=accept(sockfd,(struct sockaddr *)&cliente,&clilen);
      if((pid=fork())==0) {
         ...
      } else {
         close(connfd);
      }
  }

I removed all irrelevant parts. Now tell me, what happens to the child, once it completed the transfer?

On line 51 why are you closing the server socket ? Should that not be like the last step of the program ?

It is the child code. The child doesn't need to listen, and correctly closes its copy of the listener socket right away.

Thanks for posting the code. Yet again, as soon as I was able to compile it, run it, and generally play with it, the problem became obvious.

I removed all irrelevant parts. Now tell me, what happens to the child, once it completed the transfer?

It is the child code. The child doesn't need to listen, and correctly closes its copy of the listener socket right away.

If i'm not mistaken, each child, once completed the transfer closes the file at line 63 and closes connfd at line 64. I don't entirely understand where the problem is, i'm sorry nezachem.

If i'm not mistaken, each child, once completed the transfer closes the file at line 63 and closes connfd at line 64...

... and then exits the if clause, and continues the loop from the beginning. Since it already closed the sockfd, accept() returns immediately with an error, and the loop repeats, eating up all the available processor time.

You are missing a vital call in the child code. It is not related to the networking, but to the process life cycle. Try to figure it out yourself.

... and then exits the if clause, and continues the loop from the beginning. Since it already closed the sockfd, accept() returns immediately with an error, and the loop repeats, eating up all the available processor time.

You are missing a vital call in the child code. It is not related to the networking, but to the process life cycle. Try to figure it out yourself.

Ok, i think i've pretty much solved the problem.
I just put an 'exit(0)' call right in the end of the if loop, and everything runs fine now. Now i just need to test the execl command, and that's about it. I hope i don't need to come here to complain about the execl not working, hehe.

Thank you very much.

That was it. Good luck. Don't forget to mark the thread solved.

OK, i'm going to leave this thread open just in case i need help with execl, so i needn't open a new thread. As soon as i have everything done, i'll totally mark this thread solved.

I finished the whole program yesterday, so i consider this thread solved. Thanks a lot!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.