是否可以添加多个服务器地址? (Asio,客户端->服务器)

Is it possible to add multiple server adresses? (Asio, Client->Server)

我写了一个小的C++ asio程序,现在我想给客户端的服务器"list"添加一个备份服务器。客户端正在尝试通过 asio 解析器连接到服务器,但如果服务器离线,客户端应该会自动连接到 "backup server"。那么我可以向解析器添加多个地址还是需要编写整个 "try to connect -> fail -> try to connect to next server" 函数?

Asio 不提供这种 "skip and try another server" 功能 out-of-the-box。您需要自己编写该代码。

虽然另一个答案正确地断言你正在寻找的东西完全不存在,你可以很容易构建它:

struct multi_iterator : tcp::resolver::iterator {
    using base = typename tcp::resolver::iterator;

    multi_iterator() = default;
    template <typename T>
    explicit multi_iterator(T&& v) : base(std::forward<T>(v)) {}

    using base::values_;
    void append(tcp::resolver::results_type const& r) {
        if (!values_) values_.reset(new typename base::values_type);
        values_->insert(values_->end(), r.begin(), r.end());
    }
};

现在您可以组合多个查询的结果:

multi_iterator it;
std::vector<tcp::resolver::query> queries {
    { "localhost",  "8080"  },
    { "localhost",  "8081"  },
    { "google.com", "https" },
    { "localhost",  "6767"  },
};
for (auto query : queries)
    it.append(tcp::resolver(io).resolve(query));

使用boost::asio::connectboost::asio::async_connect进行端点迭代:

tcp::socket sock(io);
auto ep = *boost::asio::connect(sock, it);
std::cout << "Connected to " << ep.endpoint() << " (for " << ep.host_name() << ":" << ep.service_name() << ")\n";

在我的系统上打印

Connected to 172.217.19.206:443 (for google.com:https)

因为我没有在本地侦听端口 8080 或 8081。打开其中一个后 netcat -l -p 8081:

Connected to 127.0.0.1:8081 (for localhost:8081)

完整演示

还包括更通用的 basic_multi_iterator<Protocol>:

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

template <typename Proto>
struct basic_multi_iterator : boost::asio::ip::basic_resolver<Proto>::iterator {
    using resolver = typename boost::asio::ip::basic_resolver<Proto>;
    using base = typename resolver::iterator;

    basic_multi_iterator() = default;
    template <typename T> explicit basic_multi_iterator(T&& v)
        : base(std::forward<T>(v))
    {}

    using base::values_;
    void append(typename resolver::results_type const& r) {
        if (!values_) 
            values_.reset(new typename base::values_type);
        values_->insert(values_->end(), r.begin(), r.end());
    }
};

using boost::asio::ip::tcp;
using multi_iterator = basic_multi_iterator<tcp>;

int main() {
    boost::asio::io_context io;

    multi_iterator it;
    std::vector<tcp::resolver::query> queries {
        { "localhost",  "8080"  },
        { "localhost",  "8081"  },
        { "google.com", "https" },
        { "localhost",  "6767"  },
    };
    for (auto query : queries)
        it.append(tcp::resolver(io).resolve(query));

    try {
        tcp::socket sock(io);
        auto ep = *boost::asio::connect(sock, it);

        std::cout << "Connected to " << ep.endpoint() << " (for " << ep.host_name() << ":" << ep.service_name() << ")\n";
    } catch (boost::system::system_error const& e) {
        std::cout << e.what() << " - " << e.code().message() << "\n";
    }
}