Question

I'm working on an application where I need to send a "filename", "filesize" and the filedata over the network. I created a server using boost which, for now, reads in the filesize and name.

I'm wondering how I can fill a buffer with the file data (if necessary) and how to transfer it to the server.

This is what I've got now:

#ifndef OFXFILETRANSFERSENDH
#define OFXFILETRANSFERSENDH

#undef check // necessary to get Boost running on Mac

#include <vector> 
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>

#include "ofxFileTransferConnection.h"
using boost::asio::ip::tcp;
class ofxFileTransferSend : public boost::enable_shared_from_this<connection> {
public:
    typedef boost::shared_ptr<ofxFileTransferSend> pointer;
    static pointer create(
                        boost::asio::io_service& rIOService
                        ,std::string sServer
                        ,const char* sPort) 
    {
        return pointer(new ofxFileTransferSend(rIOService,sServer, sPort));
    }


private:
    //--------------------------------------------------------------
    ofxFileTransferSend(
                    boost::asio::io_service &rIOService
                    ,const std::string sServer
                    ,const char* sPort
    )
        :port(sPort)
        ,socket_(rIOService)
        ,resolver_(rIOService)
    {

        tcp::resolver::query query(sServer, sPort);
        resolver_.async_resolve(
                            query
                            ,boost::bind(
                                    &ofxFileTransferSend::handleResolve
                                    ,this
                                    ,boost::asio::placeholders::error
                                    ,boost::asio::placeholders::iterator
                            )
        );
    }


    //--------------------------------------------------------------
    void handleResolve(
        const boost::system::error_code &rError
        ,tcp::resolver::iterator oEndPointIterator
    )
    {
        if (!rError) {
            tcp::endpoint end_point = *oEndPointIterator;
            socket_.async_connect(
                                end_point
                                ,boost::bind(
                                    &ofxFileTransferSend::handleConnect
                                    ,this
                                    ,boost::asio::placeholders::error
                                    ,++oEndPointIterator
                                )
            );
        }
        else {
            std::cout << "Error while resolving server: " << std::endl;
        }
    }

    //--------------------------------------------------------------
    void handleConnect(
        const boost::system::error_code &rError
        ,tcp::resolver::iterator rOEndPointIterator
    )
    {
        if(!rError) {
            std::cout << "Connected to remote server!" << std::endl;
            std::size_t size = 1235;
            std::ostream send_data_stream(&send_data);
            send_data_stream << "filename.jpg" << "\r\n";
            send_data_stream << size << "\r\n";

            boost::asio::async_write(
                            socket_
                            ,send_data
                            ,boost::bind(
                                &ofxFileTransferSend::handleSendFileInfo
                                ,this
                                ,boost::asio::placeholders::error
                            )
            );
        }
        else {
            // @todo on failure retry!
            std::cout << "Error connecting to ofxFileTransferServer:" << rError.message()<< std::endl;
        }
    }


    //--------------------------------------------------------------
    void handleSendFileInfo(
        const boost::system::error_code &rError
    )
    {
        if(!rError) {
            cout << "okay nice, send file data done!\n";
        }
        else {
            std::cout << "Error sending file info: " << rError.message() << std::endl;
        }
    }   

    tcp::resolver resolver_;
    tcp::socket socket_;
    boost::asio::streambuf send_data;
    const char* port;
};
#endif
Was it helpful?

Solution

How about just dumping the file on the wire? That's how HTTP does it. In fact, I see you are using almost the same protocol as HTTP. Send all metadata as clear text first (name, size, etc), put in an empty line as a terminator for the metadata (\r\n) and now all you need is to dump the file itself:

void handleSendFileInfo(
    const boost::system::error_code &rError
)
{
    if(!rError) {
        std::ofstream fileData(fileName);

        boost::asio::async_write(
                        socket_
                        ,fileData
                        ,boost::bind(
                            &ofxFileTransferSend::handleSendFileData
                            ,this
                            ,boost::asio::placeholders::error
                        )
        );
    }
    else {
        std::cout << "Error sending file info: " << rError.message() << std::endl;
    }
}   
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top