0
votes

Im trying to develop an internal scanner for our infrastructure and I have started looking into boost asio to launch 254 connection at the time.

I havent found any example in boost asio documentation that would point me in the right direction.

I would like to create 254 instances of an object that would each connect and read using async_read_until, using the io_service.

What would be a correct approach to use multiple tcp::resolver and multiple tcp::socket from boost (idealy one per class?)

Also i see some complaints about resolver and socket not movable

I have very basic code and not too sure where to head next... I would appreciate any inputs. Thanks.

main.cpp :

#include <cstdlib>
#include <iostream>
#include <vector>
#include <thread>

#include <boost/asio.hpp>

#include "Harvester.hpp"

int main(int argc, char* argv[]) {

    if (argc != 2) {
        std::cerr << "Usage: harvest <range> IE: 10.30.0" << std::endl;
        return EXIT_FAILURE;
    }

    boost::asio::io_service io_service;

    // Launch the io_service thread ...
    std::thread t([&io_service]() { io_service.run(); });

    // do a bunch of stuff
    std::string range(argv[1]);
    std::cout << "Range is " << range << std::endl;
    // Build up a list of harvester
    std::string tempRange;

    std::vector<Harvester> harvesters;
    //harvesters.reserve(254);

    for (int x=1; x<255; x++) {
        tempRange = range + "." + std::to_string(x);
        std::cout << "Going to harvest " << tempRange << std::endl;
        harvesters.emplace_back( io_service );
    }
    t.join();
    return EXIT_SUCCESS;
}

harvester.hpp :

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

using boost::asio::ip::tcp;

class Harvester {
    public:
        Harvester(boost::asio::io_service &io_service);
        Harvester(const Harvester&&); // move constructor..
        void connectTo(std::string &ip);
        void doRead();
        void closeConnection();
    private:
        std::string receivedData;
        boost::asio::io_service &io_service_;
        //tcp::resolver resolver;
        tcp::socket socket_;
};

Harvester.cpp

#include "Harvester.hpp"

Harvester::Harvester(boost::asio::io_service &io_service) : io_service_(io_service), socket_(io_service) {

}

// This is for the emplace_back? Create a new object and move into the vector (this break everything big time)
Harvester::Harvester(const Harvester&& other) {
    io_service_ = other.io_service_;
    socket_ = other.socket_;
}

void Harvester::connectTo(std::string &ip) {

}
1
May be this will help: stackoverflow.com/questions/17715794/…Nim

1 Answers

0
votes

Without unnecessary details, the following is what I would do:

For Harvester

class Harvester : public std::enable_shared_from_this<Harvester> {
 public:
  ~Sender() = default;

  template<typename... Args>
  static std::shared_ptr<Harvester> Create(Args&&... args) {
    return std::shared_ptr<Harvester>(new Harvester(std::forward<Args>(args)...));
  }

  void ConnectTo(const std::string& ip_address) {
    ...
    socket_.async_connect(
        endpoint,
        [self = shared_from_this()]
        (const boost::system::error_code&, size_t) {
          // possibly write/read?
        });
  }

  void DoRead() {
    ...
    socket_.async_receive(
        read_buffer_,
        [self = shared_from_this()]
        (const boost::system::error_code&, size_t) {
          // data handling
        });
  }

  void CloseConnection() {
    boost::system::error_code ec;
    socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
    socket_.close(ec);
  }

 private:
  Harvester(boost::asio::io_service& io_service) : socket_(io_service) {}
  Harvester(const Harvester&) = delete;
  Harvester(Harvester&&) = delete;
  Harvester& operator=(const Harvester&) = delete;
  Harvester& operator=(Harvester&&) = delete;

  SocketType socket_;
  MutableBuffer read_buffer_;
}

For main (leaving out whether threaded or simply asynchronous)

...
std::vector<Harvester> harvesters;
harvesters.reserve(254);
for (int i = 0; i < 254; ++i) {
  ...
  auto harvester = Harvester::Create(io_service);
  harvester->ConnectTo(...);  // or however you want to trigger the action
  harvesters.emplace_back(std::move(harvester));
}
...
for (const auto& harvester : harvesters)  // unless you've handled it already
  harvester->CloseConnection();
...

Don't worry about movability until you understand what is hidden underneath. A socket, for example, is a descriptor. Would you want to duplicate it on a move, or simply

Socket(Socket&& other) : sd_(other.sd_) { other.sd_ = -1; }

all depends on what you try to achieve.

Footnote: For emplace_back to work as intended, the object's move constructor needs to be declared noexcept.