Solved

c socket programming : file transfer problem

Posted on 2008-10-12
10
14,250 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
[X]
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
  • 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
NEW Veeam Agent for Microsoft Windows

Backup and recover physical and cloud-based servers and workstations, as well as endpoint devices that belong to remote users. Avoid downtime and data loss quickly and easily for Windows-based physical or public cloud-based workloads!

 
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

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

Question has a verified solution.

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

For many of us, the  holiday season kindles the natural urge to give back to our friends, family members and communities. While it's easy for friends to notice the impact of such deeds, understanding the contributions of businesses and enterprises i…
Sometimes clients can lose connectivity with the Lotus Notes Domino Server, but there's not always an obvious answer as to why it happens.   Read this article to follow one of the first experiences I had with Lotus Notes on a client's machine, my…
There's a multitude of different network monitoring solutions out there, and you're probably wondering what makes NetCrunch so special. It's completely agentless, but does let you create an agent, if you desire. It offers powerful scalability …
Monitoring a network: why having a policy is the best policy? Michael Kulchisky, MCSE, MCSA, MCP, VTSP, VSP, CCSP outlines the enormous benefits of having a policy-based approach when monitoring medium and large networks. Software utilized in this v…
Suggested Courses
Course of the Month7 days, 23 hours left to enroll

617 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