I am working on a project which should read file as binary chunk and send it to a client
Server Side code
FILE *src = fopen("Video.mp4","rb"); // size of the video is 158 MB
int buffer = (1024*8); //chunk size of 8kb
char filebyte[buffer];
while(!feof(src)){
filebyte[0]=0; // Clearing the byte array to avoid overlapping
fread(filebyte,buffer,1,src);
send(acpt,filebyte,buffer,0);
filebyte[0]=0; // Clearing the byte array to avoid overlapping
}
fclose(src);
Client side Code
FILE *target = fopen("ReceivedVideo","wb");
int buffer = (1024*8) ; // chunk size of 8kb
char fileByte[buffer];
int stat;
while(1){
fileByte[0]=0; // Clearing the byte array to avoid overlapping
stat = recv(soc,fileByte,buffer,0);
fwrite(fileByte,buffer,1,target);
fileByte[0]=0; // Clearing the byte array to avoid overlapping
if(stat<0){
break;
}
}
fclose(target);
But whenever i send any video or any other file, The file output size of client side is always bigger than the original file which was actually sent by the sender.
I sent a video of 158 MB . When the transfer completes , the size of the generated file on the client side is 160 MB and whenever i try to open the received video at client directory, the video player throws an error
Then i tried sending a small .exe file of 46KB . Had to face same fate again. The .exe generated at client side consumes more bytes and when opened, throws an error
At last i sent a jpg image file of 16kb. At the client side , the photo consumed 19kb storage and when compared to the original image, i can clearly see some pixel misplacement or blurry or something like that in the received picture but atleast, the image viewer didnt throw an error this time.
The problem i found is, though i clear the chunk storage in server and client side like this
filebyte[0]=0; // On server side
fileByte[0]=0; // On client side
still the bytes received at server or client side (i dont really know which side is causing the problem but bit overlapping is the problem -according to me ) gets somehow overlapped and corrupts the file and makes its size bigger.
Any help on solving the problem will be appreciated Answer with Code and explanation will be given special importance to.
I am putting full Server and client codes below.
FULL SERVER SIDE CODE:
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <windows.h>
#include <winsock2.h>
#define port 8080
int main(){
int buffer = (1024)*8;
WSADATA ws;
WSAStartup(MAKEWORD(2,2),&ws);
SOCKET soc,acpt;
sockaddr_in config;
config.sin_family = AF_INET;
config.sin_addr.s_addr = inet_addr("0.0.0.0");
config.sin_port = htons(port);
/*char* msg = new char[buffer];
strcpy(msg,"Hello from Server"); */
soc = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
bind(soc,(sockaddr*)&config,sizeof(config));
listen(soc,1);
acpt = accept(soc,0,0);
FILE *src;
char filename[100]="Video.mp4";
char filebyte[buffer];
src = fopen(filename,"rb");
while(!feof(src)){
filebyte[0]=0;
fread(filebyte,buffer,1,src);
send(acpt,filebyte,buffer,0);
filebyte[0]=0;
}
fclose(src);
std::cout << "Press Enter to exit" <<std::endl;
//getchar();
return 0;
}
Full Client Code
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <windows.h>
#include <winsock2.h>
#define port 8080
int main(){
WSADATA ws;
WSAStartup(MAKEWORD(2,2),&ws);
int buffer = (1024)*8;
// char incoming[buffer];
sockaddr_in config;
config.sin_family = AF_INET;
config.sin_addr.s_addr = inet_addr("127.0.0.1");
config.sin_port = htons(port);
SOCKET soc;
soc = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
int err = connect(soc,(sockaddr*)&config,sizeof(config));
if(err!=0){
std::cout << "Could not connect" <<std::endl;
}else{
std::cout << "Connected Successfully" <<std::endl;
}
FILE *target;
int stat;
char fileByte[buffer]={0};
while(1){
fileByte[0]=0;
stat = recv(soc,fileByte,buffer,0);
fwrite(fileByte,buffer,1,target);
fileByte[0]=0;
if(stat<0){
break;
}
}
std::cout << strlen(fileByte) << std::endl;
fclose(target);
return 0;
}
Waiting for your kind replies. Thank You :-)
CodePudding user response:
In addition to the other answers/comments-
The server code is not closing the TCP connection after sending the file is complete, so the client doesn't know when to terminate its reading loop at the end of the file.
The server should either
send the file size before sending the file data. The client can then read the size first, and then stop the loop when the specified number of bytes have been received.
send a fixed header before each buffer, containing the buffer size. Then it can send a 0-length buffer after the file is done. The client can then read each header and buffer until it reads the 0-length buffer's header.
CodePudding user response:
I see the same issue two times, namely 'number of bytes'.
Try this:
int32_t readBytes;
while((readBytes = fread(filebyte, 1, buffer, src)) > 0)
send(acpt,filebyte, readBytes,0);
for the server side and, on the client side:
int stat;
while((stat = recv(soc,fileByte,buffer,0)) > 0)
fwrite(fileByte,1, stat,target);
This code is 'off the top of my head', so you may need to adapt it accordingly.
To explain what's going on: fread
will return the 'number of elements read' (see the man page for more details), which is 'less than buffer' for the last block of a file.
If you always send the whole buffer, this will result in a 'padded output', the last part being 'whatever was in the file at the position during the previous read', which leads to the problem you described.
Similarly, if you always write the whole buffer, the result file will be padded in the same way.
Edit: As has been brought to my attention, your code has yet another flaw, namely that your client will continue to wait for more data, until the server closes the connection, which does not happen.
In order to do that, you need to call
shutdown(acpt, 2);
closesocket(acpt);
after the read/send block.
Alternatively, if you want to keep the connection open, you will need to add additional information to your protocol.