#include <boost/asio/buffer.hpp>
#include <boost/asio/connect.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/read_until.hpp>
#include <boost/system/system_error.hpp>
#include <boost/asio/write.hpp>
#include <cstdlib>
#include <iostream>
#include <string>
using boost::asio::ip::tcp;
class client
{
public:
void connect(const std::string& host, const std::string& service,
std::chrono::steady_clock::duration timeout)
{
auto endpoints = tcp::resolver(io_context_).resolve(host, service);
boost::system::error_code error;
boost::asio::async_connect(socket_, endpoints,
[&](const boost::system::error_code& result_error,
const tcp::endpoint& )
{
error = result_error;
});
run(timeout);
if (error)
throw boost::system::system_error(error);
}
std::string read_line(std::chrono::steady_clock::duration timeout)
{
boost::system::error_code error;
std::size_t n = 0;
boost::asio::async_read_until(socket_,
boost::asio::dynamic_buffer(input_buffer_), '\n',
[&](const boost::system::error_code& result_error,
std::size_t result_n)
{
error = result_error;
n = result_n;
});
run(timeout);
if (error)
throw boost::system::system_error(error);
std::string line(input_buffer_.substr(0, n - 1));
input_buffer_.erase(0, n);
return line;
}
void write_line(const std::string& line,
std::chrono::steady_clock::duration timeout)
{
std::string data = line + "\n";
boost::system::error_code error;
boost::asio::async_write(socket_, boost::asio::buffer(data),
[&](const boost::system::error_code& result_error,
std::size_t )
{
error = result_error;
});
run(timeout);
if (error)
throw boost::system::system_error(error);
}
private:
void run(std::chrono::steady_clock::duration timeout)
{
io_context_.restart();
io_context_.run_for(timeout);
if (!io_context_.stopped())
{
socket_.close();
io_context_.run();
}
}
boost::asio::io_context io_context_;
tcp::socket socket_{io_context_};
std::string input_buffer_;
};
int main(int argc, char* argv[])
{
try
{
if (argc != 4)
{
std::cerr << "Usage: blocking_tcp_client <host> <port> <message>\n";
return 1;
}
client c;
c.connect(argv[1], argv[2], std::chrono::seconds(10));
auto time_sent = std::chrono::steady_clock::now();
c.write_line(argv[3], std::chrono::seconds(10));
for (;;)
{
std::string line = c.read_line(std::chrono::seconds(10));
if (line == argv[3])
break;
}
auto time_received = std::chrono::steady_clock::now();
std::cout << "Round trip time: ";
std::cout << std::chrono::duration_cast<
std::chrono::microseconds>(
time_received - time_sent).count();
std::cout << " microseconds\n";
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
return 0;
}