Copy a file over TCP socket

P

pradqdo

Hi folks,
I have a very strange problem when I try to port my client/server
program to cygwin. It is a simple shell program where the server
executes client's commands + it can send and receive files (something
like ftp server/client).

I implemented all the commands which the server executes from scratch
meaning I don't use fork and exec. It was very educational but my
problem is that when I try to "get <filename>" from server to the
client in cygwin the client doesn't receive the whole file. I tracked
back and saw that the read() in the server returns end of file before
reading the whole file. I think that this might be a Windows problem
or cygwin specific problem because on my home Slackware computer the
program works perfect:
The preparation for the client to receive the file includes getting
the file size:

server: snprintf(buf, 10, "%ld", (long)dir_stat.st_size); // send the
size of the file
server: s_line(buf, sockfd); // to client

So right now I am tryting to copy a file with reported size: 34302723
bytes but read return 0 (end of file) on 34302220 bytes read. This is
a problem since the client stops waiting for data only if filesize ==
numbytes sent.

Server snip:

do
{
numbytes = read(dsc, buf, sizeof(buf));

if(numbytes == -1) {
printf("Error reading source file\n");
break;
}
else if(numbytes > 0)
{
if ( (counter = write(sockfd, buf, numbytes)) < 0)
perror("get:write to socket");
total += counter;
}
else if (numbytes == 0)
printf("so far we've got %ld", total);
} while (numbytes != 0);
}
}
printf("Bytes Sent: %ld out of %ld\nFile sent successful\n",
total, (long)dir_stat.st_size);

So the last printf line on the server itself shows that there is
difference between the filesize of the file and the actual bytes sent
to clien:
Filesize: 34302723
Clients Received: 34302220

But still the while loop breaks because read returned 0 and therefore
the numbytes == 0 which is EOF if I am not mistaken.

client snip:

numbytes = read(sockfd, buf, sizeof(buf));
download += numbytes;
kbs += numbytes; // kb/s

gettimeofday(&tp2,NULL);

time +=(tp2.tv_sec - tp1.tv_sec) + (float)(tp2.tv_usec -
tp1.tv_usec)/1e6;

if (time>800) { // probably this is a second by my understandings
printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b
\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
printf("%.2f[KB/S]\t%.4f/%.4f[MB] \t%.1f/100%%",(double)kbs /
1024, (double)download / (1024 * 1024), (double)kbytes / (1024 *
1024), (double)download * 100 / kbytes);
fflush(stdout);
kbs = 0;
time = 0;
gettimeofday(&tp1, NULL);
}

if (numbytes == -1)
perror("get:read");
else if (download == kbytes) // we match the downloaded chunk with
the filesize
{
if (numbytes > 0 && strncmp(buf, "EOF\r\n", 5)) // if there is
more data
write(file, buf, numbytes); // write last bytes before closing the
file
printf("\n%.2f[KB/S]\t%.4f/%.4f[MB] \t%.2f/100%%\n",
(double)kbs / 1024, (double)download / (1024 * 1024), (double)kbytes /
(1024 * 1024), (double)download * 100 / kbytes);
printf("\nDownloading Successful!\n");
close(file);
break;
}
else
write(file, buf, numbytes);

The client receives the file size with the string that server sends
and performs kbytes = atol(buf)

So I see that I am missing the last part of the file I transfer not
because of the socket error
but probably because the server:
1. Doesn't report the file size right
2. Doesn't read correctly until EOF is reached

By the way i am dealing with binary files so I use open().
If the server doesn't report the file size right this means that the
client must receive the whole
file but if I transfer a rar archive and I try to open it it says -
unexpected end of file found so I
guess that there is a problem which I can't figure out.

I don't know why this problem does not exist on my slackware machine!?
And one last thing - the # of bytes the server reports as read are the
number of bytes that
the client actually received - so I don't know why the server read()
doesn't proceed to the end
of the file?

Any help will be appreciated.
 
D

Default User

Hi folks,
I have a very strange problem when I try to port my client/server
program to cygwin. It is a simple shell program where the server
executes client's commands + it can send and receive files (something
like ftp server/client).

Cygwin has a mailing list. That's probably the best place for porting
questions. In addition, network questions are not generally topical
here, as standard C doesn't define any such mechanisms.




Brian
 
S

Stephen Sprunk

I have a very strange problem when I try to port my client/server
program to cygwin. It is a simple shell program where the
server executes client's commands + it can send and receive
files (something like ftp server/client).

... my problem is that when I try to "get <filename>" from server
to the client in cygwin the client doesn't receive the whole file. I
tracked back and saw that the read() in the server returns end of
file before reading the whole file. I think that this might be a
Windows problem or cygwin specific problem because on my
home Slackware computer the program works perfect:

<OT>
I suggest you look at your open() call and make sure you're passing
O_BINARY; Windows forces you to be explicit when you're opening binary files
and Cygwin can't hide that problem from you. More details at:

http://www.cygwin.com/cygwin-ug-net/using-textbinary.html

Just using open() doesn't mean you don't have this issue; you have to call
it correctly, just like fopen().
</OT>

S
 
S

SM Ryan

(e-mail address removed) wrote:
# do
# {
# numbytes = read(dsc, buf, sizeof(buf));
#
# if(numbytes == -1) {
# printf("Error reading source file\n");
# break;
# }
# else if(numbytes > 0)
# {
# if ( (counter = write(sockfd, buf, numbytes)) < 0)
# perror("get:write to socket");
# total += counter;
# }

On unix, write is not guarenteed to write all bytes in the call.

You can check with
if (numbytes>counter) printf("incomplete write %ld %ld\n",numbytes,counter);

# else if (numbytes == 0)
# printf("so far we've got %ld", total);
# } while (numbytes != 0);
# }
# }
 
P

pradqdo

Thanks for the replays guys :). The O_BINARY mode is not available on
my Slackware (it says not defined) but it is available in cygwin and
it fixed my problem (in windows xp under vmware). I still have to
check this out on a true windows machine but I don't see why it is not
going to work.

Thanks Again!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top