提升asio一对多连接

时间:2021-08-27 06:06:50

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.

我正在尝试为我们的基础设施开发内部扫描仪,我已经开始考虑使用boost asio来启动254连接。

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

我没有在boost asio文档中找到任何可以指向正确方向的示例。

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

我想使用io_service创建254个对象实例,每个对象使用async_read_until进行连接和读取。

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

从boost中使用多个tcp :: resolver和多个tcp :: socket的正确方法是什么(理想每个类一个?)

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 个解决方案

#1


0  

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)

对于main(省略了线程还是简单的异步)

...
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.

脚注:为了使emplace_back按预期工作,需要将对象的移动构造函数声明为noexcept。

#1


0  

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)

对于main(省略了线程还是简单的异步)

...
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.

脚注:为了使emplace_back按预期工作,需要将对象的移动构造函数声明为noexcept。