The next code contains a tcp client class which should be created one or more times defined in a file (it is hard-coded for the example) and emplaced into a std::vector
object, and then connected to its corresponding server socket.
Godbolt link: https://godbolt.org/z/hzK9jhzjc
#include <chrono>
#include <thread>
#include <fstream>
#include <boost/asio.hpp>
namespace tcpsocket
{
using boost::asio::ip::tcp;
class client
{
public:
void connect(const std::string& host, const std::string& port)
{
if (host.empty() || port.empty()) return;
tcp::resolver resolver{ io_context };
tcp::resolver::results_type endpoints = resolver.resolve(host, port);
boost::asio::async_connect(socket, endpoints, [this](const boost::system::error_code& error, const tcp::endpoint /*endpoint*/)
{
if (!error)
read();
});
}
void read()
{
socket.async_read_some(boost::asio::buffer(data, max_length), [this](const boost::system::error_code& error, std::size_t bytes)
{
if (error) return socket.close();
bytes_received = bytes;
read();
});
}
void write(const std::string& msg)
{
boost::system::error_code error;
size_t bytes = socket.write_some(boost::asio::buffer(msg), error);
if (error) return socket.close();
}
void poll()
{
io_context.poll();
}
private:
std::string host;
std::string port;
size_t bytes_received{};
enum { max_length = 512 };
unsigned char data[max_length];
boost::asio::io_context io_context;
tcp::socket socket{io_context};
};
}//namespace tcpsocket
struct Cfg
{
unsigned id{};
std::string host;
std::string port;
};
struct Client
{
unsigned id{};
tcpsocket::client sck;
};
int main()
{
std::vector<Client> clients;
std::vector<Cfg> config{ {125u, "127.0.0.1", "30000"}, {137u, "127.0.0.1", "30001"} };//In real life, this would come from configuration file
for (auto&[id, host, port] : config)
{
//auto& client = clients.push_back(Client{id, {}});//This is failing (typo error with return value detected by Sehe!!!)
auto& client = clients.emplace_back(id, {});//This is failing
client.sck.connect(host, port);
}
while (true)
{
for (auto&[id, client] : clients)
client.poll();
using namespace std::chrono_literals;
std::this_thread::sleep_for(100ms);
}
}
The program is not compiling, due to an error with copying io_context/socket under my understanding, but I may be wrong in this point.
How can I fix this? And therefore, is there any better alternative to which I am doing? For example, it should be a better approach to make some tcp socket pool into the client class and use the same io_context for all them?