ultimate cause
ultimate cause

Reputation: 2294

boost::asio and synchrounous read causing compile errors

I am trying to make client and server talk and the data being communicated is a vector of structure

std::vector<element> elemvec

which is private member of a class, but we have methods to to retrieve individual elements of that vector using bloom_db.getelem(unsigned int).

It is adamantly failing to compile inside boost library code.

I understand that my knowledge on streams, buffers and serialization is highly flawed, but seems I need some hand holding as I don't want to copy code from boost examples.

Following is my code :

typedef struct elem{        //This will be seen as a POD (Plain Old Data) in boost::asio::buffer
    bool bit;
    int  count;
    uint64_t  hashSum[2];
    uint64_t  idSum;

    template <typename Archive>
        void serialize(Archive &ar, const unsigned int version){
            ar & bit;
            ar & count;
            ar & hashSum[0];ar & hashSum[1];
            ar & idSum;
        }
    }element;

    void sendData(tcp::socket& socket, boost::asio::const_buffer& data)
    {
        boost::asio::write(socket,boost::asio::buffer(data));
    }


    void getData(tcp::socket& socket, boost::asio::mutable_buffer& data)
    {
        boost::asio::read(socket, data);
    }


    void netcom_client(int portn, string serverip, bloom_filter& bloom_db){
        io_service io_service;
        ip::tcp::socket client_socket(io_service);
        boost::asio::const_buffer snd_buf;
        boost::system::error_code ec;
        element snd_elem;
        string bufdata;
        std::ostringstream os;
        boost::archive::text_oarchive out_archive {os};   //archive is connected to global stringstream object
        unsigned int i;

        client_socket.connect(tcp::endpoint(address::from_string(serverip),portn));
        //client sends the data : this loop is to send the data
        for(i=0; i< bloom_db.size(); ++i){

            ::set_elemvec(snd_elem,bloom_db.getelem(i));
            out_archive << snd_elem;            //element inserted in archive
            bufdata = os.str();
            snd_buf = boost::asio::buffer(os.str());
            sendData(client_socket,snd_buf);
        }

        cout<<"Sent "<<i<<" elements from client"<<endl<<std::flush;

    }

void netcom_server(int portn, bloom_filter& bloom_db){
    io_service io_service;
    element recv_elem;
    char bufdata[sizeof(element)];
    boost::system::error_code ec;
    bloom_filter recvd_bloomdb(4,"rcvbloom_db",4096);
    std::istringstream is(bufdata);
    boost::archive::text_iarchive in_archive {is};
    unsigned int i;

    ip::tcp::socket server_socket(io_service);
    tcp::acceptor acceptor_server(io_service,tcp::endpoint(tcp::v4(), portn));
    acceptor_server.accept(server_socket);

    for(i=0; i<recvd_bloomdb.size(); ++i){
        boost::asio::mutable_buffer rcv_buf  = boost::asio::buffer((void*)bufdata,sizeof(element));
        getData(server_socket, rcv_buf);
        in_archive >> recv_elem;
        recvd_bloomdb.tailadd_elem(recv_elem);
    }
    cout<<"Received "<<i<<" elements at server"<<endl<<std::flush;

}

First Line from Error

/usr/include/boost/asio/detail/consuming_buffers.hpp: In instantiation of ‘class boost::asio::detail::consuming_buffers<boost::asio::mutable_buffer, boost::asio::mutable_buffer>’: /usr/include/boost/asio/impl/read.hpp:45:44: required from ‘std::size_t boost::asio::read(SyncReadStream&, const MutableBufferSequence&, CompletionCondition, boost::system::error_code&) [with SyncReadStream = boost::asio::basic_stream_socket<boost::asio::ip::tcp>; MutableBufferSequence = boost::asio::mutable_buffer; CompletionCondition = boost::asio::detail::transfer_all_t; std::size_t = long unsigned int]’ /usr/include/boost/asio/impl/read.hpp:64:39: required from ‘std::size_t boost::asio::read(SyncReadStream&, const MutableBufferSequence&) [with SyncReadStream = boost::asio::basic_stream_socket<boost::asio::ip::tcp>; MutableBufferSequence = boost::asio::mutable_buffer; std::size_t = long unsigned int]’ ibflt.cpp:309:35: required from here /usr/include/boost/asio/detail/consuming_buffers.hpp:164:5: error: no type named ‘const_iterator’ in

‘class boost::asio::mutable_buffer’
     const_iterator;

/usr/include/boost/asio/detail/consuming_buffers.hpp:261:36: error: no type named ‘const_iterator’ in

‘class boost::asio::mutable_buffer’
   typename Buffers::const_iterator begin_remainder_;

Upvotes: 0

Views: 981

Answers (1)

rafix07
rafix07

Reputation: 20936

boost::asio::read takes as second argument buffer which must satisfy Mutable Buffer Sequence requirements, in 1.65 class mutable_buffers_1 does it, not mutable_buffer (it will work since 1.66 version).

So change:

void getData(tcp::socket& socket, boost::asio::mutable_buffers_1& data)
{
    boost::asio::read(socket, data);
}

and

boost::asio::mutable_buffers_1 rcv_buf = ...

    std::ostringstream os;
    //...
    snd_buf = boost::asio::buffer(os.str()); // [1]
    sendData(client_socket,snd_buf);

The above code cannot work, I mean it compiles fine but it will bring you undefined behaviour. Why?

boost::buffer doesn't make a copy of passed data. It returns just tuple (pointer to data and size of data), underlying data is not copied, buffer just wraps it.

ostringstream::str() returns string by COPY, reference. So buffer takes it, wraps into tuple and at the end of full expression this temporary string is destroyed, hence you have dangling reference in tuple returned by buffer.

Solution?

Create named string:

std::string str = os.str();
snd_buf = boost::asio::buffer(str);

Upvotes: 2

Related Questions