Solved

c socket programming : file transfer problem

Posted on 2008-10-12
10
14,210 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
ID: 22698507
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
ID: 22698618
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
ID: 22698776
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
Don't miss ATEN at NAB Show April 24-27!

Visit ATEN at NAB Show to learn how our "Seamlessly Entertaining" solutions deliver fast, precise video streaming without delays for the broadcasting and media environment. ATEN will showcase its 16x16 Modular Matrix Switch (VM1600) and KVM Over IP Solution (KE6900 series).

 
LVL 1

Author Comment

by:dtivmk
ID: 22729548
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
ID: 22729610
Yes it does, and yes zero is \0
0
 
LVL 1

Author Comment

by:dtivmk
ID: 22732969
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
ID: 22734742
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
ID: 22737706
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
ID: 22737769
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
ID: 22747006
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

On Demand Webinar - Networking for the Cloud Era

This webinar discusses:
-Common barriers companies experience when moving to the cloud
-How SD-WAN changes the way we look at networks
-Best practices customers should employ moving forward with cloud migration
-What happens behind the scenes of SteelConnect’s one-click button

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Short answer to this question: there is no effective WiFi manager in iOS devices as seen in Windows WiFi or Macbook OSx WiFi management, but this article will try and provide some amicable solutions to better suite your needs.
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.
This video gives you a great overview about bandwidth monitoring with SNMP and WMI with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're looking for how to monitor bandwidth using netflow or packet s…

713 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