Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people, just like you, are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
Solved

c socket programming : file transfer problem

Posted on 2008-10-12
10
14,188 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
Manage your data center from practically anywhere

The KN8164V features HD resolution of 1920 x 1200, FIPS 140-2 with level 1 security standards and virtual media transmissions at twice the speed. Built for reliability, the KN series provides local console and remote over IP access, ensuring 24/7 availability to all servers.

 
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

Microsoft Certification Exam 74-409

Veeam® is happy to provide the Microsoft community with a study guide prepared by MVP and MCT, Orin Thomas. This guide will take you through each of the exam objectives, helping you to prepare for and pass the examination.

Question has a verified solution.

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

Configuring network clients can be a chore, especially if there are a large number of them or a lot of itinerant users.  DHCP dynamically manages this process, much to the relief of users and administrators alike!
Meet the world's only “Transparent Cloud™” from Superb Internet Corporation. Now, you can experience firsthand a cloud platform that consistently outperforms Amazon Web Services (AWS), IBM’s Softlayer, and Microsoft’s Azure when it comes to CPU and …
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.
After creating this article (http://www.experts-exchange.com/articles/23699/Setup-Mikrotik-routers-with-OSPF.html), I decided to make a video (no audio) to show you how to configure the routers and run some trace routes and pings between the 7 sites…

839 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