Solved

c socket programming : file transfer problem

Posted on 2008-10-12
10
14,101 Views
Last Modified: 2013-12-26
Hi,
In the attached server.c and client.c code snippets, if I don't use
bzero,
then,
at the client side, some extra/strange characters appear at the end
of client.txt.

I want to know why?
server.txt is as simple as this :
----file beginning---
abcd
---file end---
All I am trying to do here is to transfer server.txt, from server to client.txt
at the client.
server.c :

#include <sys/socket.h>

#include <sys/types.h>

#include <netinet/in.h>  

#include <arpa/inet.h>

#include <stdio.h>
 

#define PORT 2080
 

main()

{

	int sock1,sock2, clength;

	sock1 =  socket(AF_INET,SOCK_STREAM,0);

	struct sockaddr_in serv,cli;
 

	serv.sin_family = AF_INET;

	serv.sin_port = htons(PORT);

	serv.sin_addr.s_addr = inet_addr("127.0.0.1");

	bind(sock1,(struct sockaddr *)&serv, sizeof(serv));

	listen(sock1,5);

	clength = sizeof(cli);

	int i=0;

	char buf[50];

	sock2 = accept(sock1,(struct sockaddr *)&cli,&clength);

	printf("\n Client Connected\n");

	FILE* fp = fopen("server.txt","r");

	while(!feof(fp)){

		//bzero(buf,sizeof(buf));

		fread(buf,sizeof(char),50,fp);

		write(sock2,buf,50);

	}

	write(sock2,"quit1234",50);

	fclose(fp);

	return 0;

}
 

client.c :

#include <sys/socket.h>

#include <sys/types.h>

#include <netinet/in.h>  

#include <arpa/inet.h>

#include <stdio.h>
 

#define PORT 2080
 

main()

{

	int sock1;

	sock1 =  socket(AF_INET,SOCK_STREAM,0);

	struct sockaddr_in serv;
 

	serv.sin_port = htons(PORT);

	printf("%x %x\n",PORT,htons(PORT));

	serv.sin_family = AF_INET;

	serv.sin_addr.s_addr = inet_addr("127.0.0.1");

	printf("client connecting\n");

	connect(sock1, (struct sockaddr *)&serv,sizeof(serv));

	char buf[50];

	FILE* fp = fopen("client.txt","w");

	while(1){

		//bzero(buf,sizeof(buf));

		read(sock1,buf,50);

		if(strcmp(buf,"quit1234")==0)

		{

			break;	

		}

		fprintf(fp,"%s",buf);

	}

	fclose(fp);

}

Open in new window

0
Comment
Question by:dtivmk
  • 5
  • 5
10 Comments
 
LVL 17

Expert Comment

by:sweetfa2
Comment Utility
You are using fprintf to output your buffer.  It expects a null terminated string for it to determine where the end of the buffer is.  bzero fills your buffer with null characters so that only characters in the buffer are the ones that you have sent and the remainder of null characters, which is why fprintf currently works for you with bzero there.

read returns a length of the buffer read.  common practice is to null terminate the buffer after the read if you intend to use printf functions, or you can restrict the length of your fprintf outpu tto the specified buffer length.
0
 
LVL 1

Author Comment

by:dtivmk
Comment Utility
I am not clear about many things here.

Suppose the file to be transferred has 54 bytes.

(i) At the server side, while reading the file

in the first iteration :
I am reading 50 characters
in fread, so there is no place left for inserting '\0' in buf.
So, how does it matter, whether bzero has been used or not?
And the client is actually receiving those 50 bytes correctly.

(ii) In the next iteration, I read 4 bytes in buf.
What happens to the rest 46 bytes in buf[50]?
Does fread change them? Or do they have
previous values assigned to them? If they have
the previous values assigned to them, then
those characters should go to the client. Instead,
some strange binary data is being transmitted.
If fread changes them, then what does it
actually do with them?
0
 
LVL 17

Expert Comment

by:sweetfa2
Comment Utility
You are creating a stack based variable for your buffer.   It is never going to be empty as is the nature of stack variables and must be initialised properly.

You have two choices, either put a null character at the end of your buffer buffer, or limit the output to the length that you have read.

If you have a 50 character buffer, there is no guarantee what is next.  buf is efffectively a pointer, and whilst you have 50 characters allocated on teh stack for it what is either side of those 50 characters is anyones guess.  You could be lucky and find a zero byte is the next one, byut then again, you most likely will not be, but that depends on the architecture of the system you are running this program on.

fprintf thinks the only way to work out where the end of a %s is is when it finds a zero byte.

You can use the attached code bits to output what you want.
int len;

len = read(sock1, buf, 50);

fprintf(fp, "%.*s", len, buf);

Open in new window

0
 
LVL 1

Author Comment

by:dtivmk
Comment Utility
Sorry for late reply.
I have few more questions.
I will ask them one by one.
Firstly, what does bzero actually do?
Does it copy zeroes or '\0's in the
array? Are both of them same?
0
 
LVL 17

Expert Comment

by:sweetfa2
Comment Utility
Yes it does, and yes zero is \0
0
Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

 
LVL 1

Author Comment

by:dtivmk
Comment Utility
thanks.
secondly,
if server.txt has 330 characters,
then client.txt has 350 characters.
So, what's happening is client.c is reading 20
more characters in the last iterations since it couldn't
locate the end of string.
But why does it read only 20 more characters?
Why doesn't it go beyond those 20 characters?
Or am I getting plain lucky here?(in the sense that
the byte after the char array is 0)
0
 
LVL 17

Accepted Solution

by:
sweetfa2 earned 500 total points
Comment Utility
No there are only 330 chars to read.  However, your server program is writing out 50 byte chunks each time which is why you have the discrepancy.

So your client is reading correctly what is being sent.  At the moment however, because both programs are working in blocks of 50 bytes you are hanging together.  When you apply fixes to your server however you will potentially get problems again if your buffer is not zeroed because it is still using the fprintf without a length (unless you have implemented my earlier suggestions)

To fix the problem fread returns a length indicating how many characters where actually read.  If you use this as the length parameter to your your write then you will get the the correct number of bytes.


                int len = fread(buf,sizeof(char),50,fp);

                write(sock2,buf,len);

        }
 

        char *quitStr = "quite1234";

        write(sock2,quitStr,strlen(quitStr));

Open in new window

0
 
LVL 1

Author Comment

by:dtivmk
Comment Utility
ok.
just one more.
suppose that 50 characters are read correctly in 'buf'
using
char buf[50];
fread(buf,sizeof(char),50,fp);
then,
if I call
fprintf(fp,"%s",buf);
is it guaranteed that buf will be printed correctly?
Since, in 'buf' there is no '\0' anywhere, so will
fprintf stop at buf[49] or will go beyond buf[49]
searching for '\0'?
0
 
LVL 17

Expert Comment

by:sweetfa2
Comment Utility
It will go beyond.  As I have said before you need

int len;
char buf[50];
len = fread(buf,sizeof(char),50,fp);

fprintf(otherfp, "%.*s", len, buf);

Notice the .* in the format string for fprintf and the additional len parameter.

That is saying print a maximum of 'len' characters, but be warned that if you have a null in your buffer then you also won't see all of the buffer that may have been read.  That is why it is better to use the basic read/write methods on sockets or files where you expect non-alphanum characters in your character set.

your example above has fprintf outputing to the same socket stream that you are reading from.  That can confuse the issue.
0
 
LVL 1

Author Comment

by:dtivmk
Comment Utility
I think this question and following discussion has become a bit confusing for me.
I would rather close this question, and restart with a fresh question later.
Thanks sweetfa2 for your patience.
0

Featured Post

Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

Join & Write a Comment

This is an article about my experiences with remote access to my clients (so that I may serve them) and eventually to my home office system via Radmin Remote Control. I have been using remote access for over 10 years and have been improving my metho…
Data center, now-a-days, is referred as the home of all the advanced technologies. In-fact, most of the businesses are now establishing their entire organizational structure around the IT capabilities.
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
In this tutorial you'll learn about bandwidth monitoring with flows and packet sniffing with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're interested in additional methods for monitoring bandwidt…

728 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

9 Experts available now in Live!

Get 1:1 Help Now