0

Hi I'm trying to send files via sockets from a server to a client and then open them on the client. My Problem is that I can send pictures and documents without a problem, but when I try to send a video the data that reaches its destination is corrupt. The destinationfile has the same size as the sourcefile.

Server

int Server::data_trans_send(Client *client, const char *filename, const char *loc){
    int re;
    //client object stores socket ID
#ifdef _WIN32
    SOCKET dest = (client->socketfd());
#else
    int dest = (client->socketfd());
#endif
    string sloc;
    int resp = 0;
    sloc.append (loc);
    sloc.append (filename);
    //opens a file in binary
    FilePrep file(sloc.c_str ());
    long int filesize = file.filesize();
    //reads binary data into a char array
    char *data = file.preptdata();
    //sends the filesize
    re = send(dest, &filesize, sizeof(long int), 0);
    if(re < 0){return -1;}
    re = 0;
    re = recv (dest, &resp, sizeof(int), 0);
    if(re < 0){return -2;}
    re = 0;
    //sends the filename
    re = write(dest, filename, strlen(filename));
    if(re < 0){return -3;}
    re = 0;
    re = recv (dest, &resp, sizeof(int), 0);
    if(re < 0){return -4;}
    re = 0;
    //sends the filedata
    re = write(dest, data, filesize);
    if(re < 0){return -5;}
    re = 0;
    re = recv (dest, &resp, sizeof(int), 0);
    if(re < 0){return -6;}
    re = 0;
    return 1;
}

Client

int Client::data_trans_recv(const char *loc){
    //server socket ID is stored in the private section of class
    long int filesize = 0;
    int re;
    int resp = 1;
    char *filename = new char[64];
    //recieves the filesize 
    re = recv(*sockfd, &filesize, sizeof(long int), 0);
    if(re < 0){return -1;}
    re = 0;
    re = send(*sockfd, &resp, sizeof(int), 0);
    if(re < 0){return -2;}
    re = 0;
    //recieves the filename 
    re = read(*sockfd, filename, 64);
    if(re < 0){return -3;}
    re = 0;
    re = send(*sockfd, &resp, sizeof(int), 0);
    if(re < 0){return -4;}
    re = 0;
    save_filename (filename);
    //creates an empty file and opens it in binary
    BuildData file(filesize);
    //returns ptr to array to write data to file
    char *dest = file.fileptr();
    //recieves the filedata 
    re = read(*sockfd, dest, filesize);
    if(re < 0){return -5;}
    re = 0;
    re = send(*sockfd, &resp, sizeof(int), 0);
    if(re < 0){return -6;}
    re = 0;
    string floc;
    floc.append (loc);
    floc.append (filename);
    //writes array to file
    file.writeData(floc.c_str (), dest);
    delete filename;
    return 1;
}

The Send and recv with the 1 integer is just to synchronize both functions.

Build Data

#include "BuildData.h"
#include <iostream>
#include <fstream>
using namespace std;

BuildData::BuildData(long int file_size) {
    data = new char[file_size];
    filesize = file_size;
}

BuildData::~BuildData() {
    delete data;
    file.close();
}

int BuildData::writeData(const char *loc, char *bits){
    file.open(loc, ios::out | ios::binary | ios::trunc);
    if(file.is_open()){
        file.write(bits, filesize);
        return 1;
    }
    return -1;
}

char *BuildData::fileptr(){return data;}
Stephan Pich
  • 171
  • 1
  • 2
  • 11
  • What is `BuildData`? It could be part of the problem. – stefaanv Aug 24 '17 at 09:01
  • 3
    Remember that `read` is not guaranteed to return the exact number of bytes as requested. Certainly not over TCP. see http://man7.org/linux/man-pages/man2/read.2.html – stefaanv Aug 24 '17 at 09:02
  • Remember also that it returned zero the peer has disconnected. You are completely ignoring that possibility. – user207421 Aug 24 '17 at 09:08
  • Thank you but I've tried it already with send/recv same outcome BuilData is an Object that creates a file in binary output and trunc – Stephan Pich Aug 24 '17 at 09:11
  • Consider using the `htonl()` functions for ensuring that the byte ordering is correct across hosts with differing endianness. – Mark Setchell Aug 24 '17 at 09:11
  • `recv` also doesn't guarantee the number of received bytes. repeat the request until all requested bytes are received. Check the return-value and advance the pointer for receiving the rest of the bytes. – stefaanv Aug 24 '17 at 09:15
  • Well, do you use TCP or UDP to send data? (SOCK_STREAM or SOCK_DGRAM in socket creation?). In UDP packets order may differ to the one they were sent. – R2RT Aug 24 '17 at 09:16
  • @stefaanv I've tried that as well same outcome – Stephan Pich Aug 24 '17 at 09:17
  • @T2RT I'm using TCP – Stephan Pich Aug 24 '17 at 09:17
  • 3
    It will not work with large files until you put your `read()` calls inside a loop. – Mark Setchell Aug 24 '17 at 09:20
  • You still have not shown what `BuildData` is, so we can only look at the given code which is incomplete. Add logs so you can check that what you send and what you recieve is the same and you can check where the change comes from. Wireshark is also an excellent tool for network programming. – stefaanv Aug 24 '17 at 09:24
  • In this case, when sending a large amount of data, read will return long before all the data is sent. The smaller files probably fit inside your TCP buffer and as a result can be read in a single hit (by luck). For larger files you need to continue to read until all data is received. – djgandy Aug 24 '17 at 09:54
  • See https://stackoverflow.com/questions/666601/what-is-the-correct-way-of-reading-from-a-tcp-socket-in-c-c for an example of a loop on read with socket – Clonk Aug 24 '17 at 11:45
  • Thank you guys its working now!! – Stephan Pich Aug 27 '17 at 11:13

0 Answers0