0

I have a client and a server code. Both the snippets are shown below. From the client, I am trying to send a vector but at the server end, I am not able to receive it.. Any hints exactly in the code whats wrong and how to fix it..

A working example of the same using "asynchronous asio" is there in boost examples : http://www.boost.org/doc/libs/1_38_0/doc/html/boost_asio/example/serialization/client.cpp http://www.boost.org/doc/libs/1_38_0/doc/html/boost_asio/example/serialization/server.cpp

But, I am using synchronous asio .....

Client Code (See sendRequest() Function )

#include <boost/asio.hpp>
#include <iostream>

using namespace boost;

struct stock
{
  std::string code;
  std::string name;
  double open_price;
  double high_price;
  double low_price;
  double last_price;
  double buy_price;
  int buy_quantity;
  double sell_price;
  int sell_quantity;

  template <typename Archive>
  void serialize(Archive& ar, const unsigned int version)
  {
    ar & code;
    ar & name;
    ar & open_price;
    ar & high_price;
    ar & low_price;
    ar & last_price;
    ar & buy_price;
    ar & buy_quantity;
    ar & sell_price;
    ar & sell_quantity;
  }
};

class SyncTCPClient {
public:
    SyncTCPClient(const std::string& raw_ip_address,
        unsigned short port_num) :
        m_ep(asio::ip::address::from_string(raw_ip_address),
        port_num),
        m_sock(m_ios) {

        m_sock.open(m_ep.protocol());
    }

    void connect() {
        m_sock.connect(m_ep);
    }

    void close() {
        m_sock.shutdown(
            boost::asio::ip::tcp::socket::shutdown_both);
        m_sock.close();
    }

    std::string emulateLongComputationOp(
        unsigned int duration_sec) {

        std::string request = "EMULATE_LONG_COMP_OP "
            + std::to_string(duration_sec)
            + "\n";

        sendRequest(request);
        return receiveResponse();
    };

private:
    void sendRequest(const std::string& request) {

        std::vector<stock> stocks_;
        // Create the data to be sent to each client.
    stock s;
    s.code = "ABC";
    s.name = "A Big Company";
    s.open_price = 4.56;
    s.high_price = 5.12;
    s.low_price = 4.33;
    s.last_price = 4.98;
    s.buy_price = 4.96;
    s.buy_quantity = 1000;
    s.sell_price = 4.99;
    s.sell_quantity = 2000;
    stocks_.push_back(s);
    s.code = "DEF";
    s.name = "Developer Entertainment Firm";
    s.open_price = 20.24;
    s.high_price = 22.88;
    s.low_price = 19.50;
    s.last_price = 19.76;
    s.buy_price = 19.72;
    s.buy_quantity = 34000;
    s.sell_price = 19.85;
    s.sell_quantity = 45000;
    stocks_.push_back(s);

        asio::write(m_sock, asio::buffer(stocks_));

        //asio::write(m_sock, asio::buffer(request));
    }

    std::string receiveResponse() {
        std::string response;
        return response;
    }

private:
    asio::io_service m_ios;

    asio::ip::tcp::endpoint m_ep;
    asio::ip::tcp::socket m_sock;
};

int main()
{
    const std::string raw_ip_address = "127.0.0.1";
    const unsigned short port_num = 3333;

    try {
        SyncTCPClient client(raw_ip_address, port_num);

        // Sync connect.
        client.connect();

        std::cout << "Sending request to the server... "
            << std::endl;

        std::string response =
            client.emulateLongComputationOp(10);

        std::cout << "Response received: " << response
            << std::endl;

        // Close the connection and free resources.
        client.close();
    }
    catch (system::system_error &e) {
        std::cout << "Error occured! Error code = " << e.code()
            << ". Message: " << e.what();

        return e.code().value();
    }

    return 0;
}

Server Code (See HandleClient() code ) stocks_.size() is coming as 0

#include <boost/asio.hpp>

#include <thread>
#include <atomic>
#include <memory>
#include <iostream>

using namespace boost;

struct stock
{
  std::string code;
  std::string name;
  double open_price;
  double high_price;
  double low_price;
  double last_price;
  double buy_price;
  int buy_quantity;
  double sell_price;
  int sell_quantity;

  template <typename Archive>
  void serialize(Archive& ar, const unsigned int version)
  {
    ar & code;
    ar & name;
    ar & open_price;
    ar & high_price;
    ar & low_price;
    ar & last_price;
    ar & buy_price;
    ar & buy_quantity;
    ar & sell_price;
    ar & sell_quantity;
  }
};

class Service {
public:
    Service(){}

    void StartHandligClient(
        std::shared_ptr<asio::ip::tcp::socket> sock) {

        std::thread th(([this, sock]() {
            HandleClient(sock);
        }));

        th.detach();
    }

private:
    void HandleClient(std::shared_ptr<asio::ip::tcp::socket> sock) {
        try {

            //Read stocks structure
            std::vector<stock> stocks_;
            asio::read(*sock.get(), asio::buffer(stocks_));

            std::cout << "stocks_.size() : " << stocks_.size() << "\n";
            // Print out the data that was received.
            for (std::size_t i = 0; i < stocks_.size(); ++i)
            {
                std::cout << "Stock number " << i << "\n";
                std::cout << "  code: " << stocks_[i].code << "\n";
                std::cout << "  name: " << stocks_[i].name << "\n";
                std::cout << "  open_price: " << stocks_[i].open_price << "\n";
                std::cout << "  high_price: " << stocks_[i].high_price << "\n";
                std::cout << "  low_price: " << stocks_[i].low_price << "\n";
                std::cout << "  last_price: " << stocks_[i].last_price << "\n";
                std::cout << "  buy_price: " << stocks_[i].buy_price << "\n";
                std::cout << "  buy_quantity: " << stocks_[i].buy_quantity << "\n";
                std::cout << "  sell_price: " << stocks_[i].sell_price << "\n";
                std::cout << "  sell_quantity: " << stocks_[i].sell_quantity << "\n";
            }            

        }
        catch (system::system_error &e) {
            std::cout << "Error occured! Error code = "
                << e.code() << ". Message: "
                << e.what();
        }

        // Clean-up.
        delete this;
    }
};

class Acceptor {
public:
    Acceptor(asio::io_service& ios, unsigned short port_num) :
        m_ios(ios),
        m_acceptor(m_ios,
        asio::ip::tcp::endpoint(
        asio::ip::address_v4::any(),
        port_num))
    {
        m_acceptor.listen();
    }

    void Accept() {
        std::cout << "Server Accept() \n" << std::flush;
        std::shared_ptr<asio::ip::tcp::socket>
            sock(new asio::ip::tcp::socket(m_ios));

        m_acceptor.accept(*sock.get());

        (new Service)->StartHandligClient(sock);
    }

private:
    asio::io_service& m_ios;
    asio::ip::tcp::acceptor m_acceptor;
};

class Server {
public:
    Server() : m_stop(false) {}

    void Start(unsigned short port_num) {
        m_thread.reset(new std::thread([this, port_num]() {
            Run(port_num);
        }));
    }

    void Stop() {
        m_stop.store(true);
        m_thread->join();
    }

private:
    void Run(unsigned short port_num) {
        Acceptor acc(m_ios, port_num);

        while (!m_stop.load()) {
            std::cout << "Server accept\n" << std::flush;
            acc.Accept();
        }
    }

    std::unique_ptr<std::thread> m_thread;
    std::atomic<bool> m_stop;
    asio::io_service m_ios;
};

int main()
{
    unsigned short port_num = 3333;

    try {
        Server srv;
        srv.Start(port_num);

        std::this_thread::sleep_for(std::chrono::seconds(60));

        srv.Stop();
    }
    catch (system::system_error &e) {
        std::cout << "Error occured! Error code = "
            << e.code() << ". Message: "
            << e.what();
    }

    return 0;
}

Please note that the same code works fine when passing strings from client to server.

Nishant Sharma
  • 341
  • 2
  • 5
  • 17
  • Looking at the asio docs, asio::buffer on a `vector` gives a constant buffer so you can not write to it in the server. Look up `asio::buffer` in the documentation and you can see why this is so. – Justin Finnerty Nov 24 '17 at 10:42
  • Linked duplicate shows what's happening. In your code there's boost serialization, but no use of it (an archive). That's the design error. See here for simple demonstration https://stackoverflow.com/questions/47236474/sending-receiving-a-struct-in-boostasio/47243908#47243908 – sehe Nov 24 '17 at 16:14
  • @sehe ... I did go through an example in documentation where asynchronous asio was used and it was mentioned that the asynchronous write itself does the serialisation if the class has a serialize function defined. See the links I have mentioned..... And it worked fine in that case... I am trying with synchronous write and read... can you let me know what is to be corrected in this program I mentioned ? – Nishant Sharma Nov 25 '17 at 05:51
  • @NishantSharma see http://www.boost.org/doc/libs/1_65_1/doc/html/boost_asio/example/cpp03/serialization/connection.hpp `async_write`: it's a member function of `connection` and it does indeed use `text_oarchive`. (The only confusing part here is that the name is also `async_write`) – sehe Nov 25 '17 at 09:31

0 Answers0