views:

39

answers:

1

Hi!

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
+1  A: 

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;
    }
}   
Gianni
Hi Gianni, thanks a lot for your reply! Will this correctly send -all- data? Or is all the data send in chunks and do I need to call this async_write() multiple times with chunks?
pollux
This should the all the data. No need for anything else really.
Gianni
Hi Gianni, I'm going to try it tomorrow.. my code is at work. But thanks a lot! Didn't expect it to be so easy!
pollux
@pollux Glad to be of help. But, I think you should try it out before accepting the answer. You can never be sure whats going to happen. ;-)
Gianni