diff options
author | 2021-11-15 04:15:13 +1100 | |
---|---|---|
committer | 2021-11-15 04:15:13 +1100 | |
commit | 44ec6d2e0ee569202b75b73eea40972595866779 (patch) | |
tree | b286443c264704198789514e0594dc24b3ca9f96 /3rdparty/asio/src/examples/cpp03/timeouts/blocking_tcp_client.cpp | |
parent | 137f254b918f1f1ebee43dfbed86793b0dae73eb (diff) |
3rdparty: Updated ASIO to version 1.20.0.
The doc folder isn't included as it's pretty big.
This required include/asio/detail/win_iocp_socket_accept_op.hpp due to
mismatched order in the member declarations and initialiser list for the
win_iocp_socket_accept_op class. I reversed the declaration order so it
matches win_iocp_socket_move_accept_op.
Diffstat (limited to '3rdparty/asio/src/examples/cpp03/timeouts/blocking_tcp_client.cpp')
-rw-r--r-- | 3rdparty/asio/src/examples/cpp03/timeouts/blocking_tcp_client.cpp | 207 |
1 files changed, 78 insertions, 129 deletions
diff --git a/3rdparty/asio/src/examples/cpp03/timeouts/blocking_tcp_client.cpp b/3rdparty/asio/src/examples/cpp03/timeouts/blocking_tcp_client.cpp index 69d467af1bb..67d0bcc7604 100644 --- a/3rdparty/asio/src/examples/cpp03/timeouts/blocking_tcp_client.cpp +++ b/3rdparty/asio/src/examples/cpp03/timeouts/blocking_tcp_client.cpp @@ -2,199 +2,146 @@ // blocking_tcp_client.cpp // ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // +#include "asio/buffer.hpp" #include "asio/connect.hpp" -#include "asio/deadline_timer.hpp" #include "asio/io_context.hpp" #include "asio/ip/tcp.hpp" #include "asio/read_until.hpp" -#include "asio/streambuf.hpp" #include "asio/system_error.hpp" #include "asio/write.hpp" -#include "asio/thread.hpp" #include <cstdlib> #include <iostream> #include <string> #include <boost/lambda/bind.hpp> #include <boost/lambda/lambda.hpp> -using asio::deadline_timer; using asio::ip::tcp; using boost::lambda::bind; using boost::lambda::var; using boost::lambda::_1; +using boost::lambda::_2; //---------------------------------------------------------------------- // -// This class manages socket timeouts by applying the concept of a deadline. -// Each asynchronous operation is given a deadline by which it must complete. -// Deadlines are enforced by an "actor" that persists for the lifetime of the -// client object: -// -// +----------------+ -// | | -// | check_deadline |<---+ -// | | | -// +----------------+ | async_wait() -// | | -// +---------+ -// -// If the actor determines that the deadline has expired, the socket is closed -// and any outstanding operations are consequently cancelled. The socket -// operations themselves use boost::lambda function objects as completion -// handlers. For a given socket operation, the client object runs the -// io_context to block thread execution until the actor completes. +// This class manages socket timeouts by running the io_context using the timed +// io_context::run_for() member function. Each asynchronous operation is given +// a timeout within which it must complete. The socket operations themselves +// use boost::lambda function objects as completion handlers. For a given +// socket operation, the client object runs the io_context to block thread +// execution until the operation completes or the timeout is reached. If the +// io_context::run_for() function times out, the socket is closed and the +// outstanding asynchronous operation is cancelled. // class client { public: client() - : socket_(io_context_), - deadline_(io_context_) + : socket_(io_context_) { - // No deadline is required until the first socket operation is started. We - // set the deadline to positive infinity so that the actor takes no action - // until a specific deadline is set. - deadline_.expires_at(boost::posix_time::pos_infin); - - // Start the persistent actor that checks for deadline expiry. - check_deadline(); } void connect(const std::string& host, const std::string& service, - boost::posix_time::time_duration timeout) + asio::chrono::steady_clock::duration timeout) { // Resolve the host name and service to a list of endpoints. tcp::resolver::results_type endpoints = tcp::resolver(io_context_).resolve(host, service); - // Set a deadline for the asynchronous operation. As a host name may - // resolve to multiple endpoints, this function uses the composed operation - // async_connect. The deadline applies to the entire operation, rather than - // individual connection attempts. - deadline_.expires_from_now(timeout); - - // Set up the variable that receives the result of the asynchronous - // operation. The error code is set to would_block to signal that the - // operation is incomplete. Asio guarantees that its asynchronous - // operations will never fail with would_block, so any other value in - // ec indicates completion. - asio::error_code ec = asio::error::would_block; - // Start the asynchronous operation itself. The boost::lambda function // object is used as a callback and will update the ec variable when the // operation completes. The blocking_udp_client.cpp example shows how you // can use boost::bind rather than boost::lambda. + asio::error_code ec; asio::async_connect(socket_, endpoints, var(ec) = _1); - // Block until the asynchronous operation has completed. - do io_context_.run_one(); while (ec == asio::error::would_block); - - // Determine whether a connection was successfully established. The - // deadline actor may have had a chance to run and close our socket, even - // though the connect operation notionally succeeded. Therefore we must - // check whether the socket is still open before deciding if we succeeded - // or failed. - if (ec || !socket_.is_open()) - throw asio::system_error( - ec ? ec : asio::error::operation_aborted); + // Run the operation until it completes, or until the timeout. + run(timeout); + + // Determine whether a connection was successfully established. + if (ec) + throw asio::system_error(ec); } - std::string read_line(boost::posix_time::time_duration timeout) + std::string read_line(asio::chrono::steady_clock::duration timeout) { - // Set a deadline for the asynchronous operation. Since this function uses - // a composed operation (async_read_until), the deadline applies to the - // entire operation, rather than individual reads from the socket. - deadline_.expires_from_now(timeout); - - // Set up the variable that receives the result of the asynchronous - // operation. The error code is set to would_block to signal that the - // operation is incomplete. Asio guarantees that its asynchronous - // operations will never fail with would_block, so any other value in - // ec indicates completion. - asio::error_code ec = asio::error::would_block; - - // Start the asynchronous operation itself. The boost::lambda function - // object is used as a callback and will update the ec variable when the - // operation completes. The blocking_udp_client.cpp example shows how you - // can use boost::bind rather than boost::lambda. - asio::async_read_until(socket_, input_buffer_, '\n', var(ec) = _1); - - // Block until the asynchronous operation has completed. - do io_context_.run_one(); while (ec == asio::error::would_block); - + // Start the asynchronous operation. The boost::lambda function object is + // used as a callback and will update the ec variable when the operation + // completes. The blocking_udp_client.cpp example shows how you can use + // boost::bind rather than boost::lambda. + asio::error_code ec; + std::size_t n = 0; + asio::async_read_until(socket_, + asio::dynamic_buffer(input_buffer_), + '\n', (var(ec) = _1, var(n) = _2)); + + // Run the operation until it completes, or until the timeout. + run(timeout); + + // Determine whether the read completed successfully. if (ec) throw asio::system_error(ec); - std::string line; - std::istream is(&input_buffer_); - std::getline(is, line); + std::string line(input_buffer_.substr(0, n - 1)); + input_buffer_.erase(0, n); return line; } void write_line(const std::string& line, - boost::posix_time::time_duration timeout) + asio::chrono::steady_clock::duration timeout) { std::string data = line + "\n"; - // Set a deadline for the asynchronous operation. Since this function uses - // a composed operation (async_write), the deadline applies to the entire - // operation, rather than individual writes to the socket. - deadline_.expires_from_now(timeout); - - // Set up the variable that receives the result of the asynchronous - // operation. The error code is set to would_block to signal that the - // operation is incomplete. Asio guarantees that its asynchronous - // operations will never fail with would_block, so any other value in - // ec indicates completion. - asio::error_code ec = asio::error::would_block; - - // Start the asynchronous operation itself. The boost::lambda function - // object is used as a callback and will update the ec variable when the - // operation completes. The blocking_udp_client.cpp example shows how you - // can use boost::bind rather than boost::lambda. + // Start the asynchronous operation. The boost::lambda function object is + // used as a callback and will update the ec variable when the operation + // completes. The blocking_udp_client.cpp example shows how you can use + // boost::bind rather than boost::lambda. + asio::error_code ec; asio::async_write(socket_, asio::buffer(data), var(ec) = _1); - // Block until the asynchronous operation has completed. - do io_context_.run_one(); while (ec == asio::error::would_block); + // Run the operation until it completes, or until the timeout. + run(timeout); + // Determine whether the read completed successfully. if (ec) throw asio::system_error(ec); } private: - void check_deadline() + void run(asio::chrono::steady_clock::duration timeout) { - // Check whether the deadline has passed. We compare the deadline against - // the current time since a new asynchronous operation may have moved the - // deadline before this actor had a chance to run. - if (deadline_.expires_at() <= deadline_timer::traits_type::now()) + // Restart the io_context, as it may have been left in the "stopped" state + // by a previous operation. + io_context_.restart(); + + // Block until the asynchronous operation has completed, or timed out. If + // the pending asynchronous operation is a composed operation, the deadline + // applies to the entire operation, rather than individual operations on + // the socket. + io_context_.run_for(timeout); + + // If the asynchronous operation completed successfully then the io_context + // would have been stopped due to running out of work. If it was not + // stopped, then the io_context::run_for call must have timed out. + if (!io_context_.stopped()) { - // The deadline has passed. The socket is closed so that any outstanding - // asynchronous operations are cancelled. This allows the blocked - // connect(), read_line() or write_line() functions to return. - asio::error_code ignored_ec; - socket_.close(ignored_ec); - - // There is no longer an active deadline. The expiry is set to positive - // infinity so that the actor takes no action until a new deadline is set. - deadline_.expires_at(boost::posix_time::pos_infin); - } + // Close the socket to cancel the outstanding asynchronous operation. + socket_.close(); - // Put the actor back to sleep. - deadline_.async_wait(bind(&client::check_deadline, this)); + // Run the io_context again until the operation completes. + io_context_.run(); + } } asio::io_context io_context_; tcp::socket socket_; - deadline_timer deadline_; - asio::streambuf input_buffer_; + std::string input_buffer_; }; //---------------------------------------------------------------------- @@ -205,32 +152,34 @@ int main(int argc, char* argv[]) { if (argc != 4) { - std::cerr << "Usage: blocking_tcp <host> <port> <message>\n"; + std::cerr << "Usage: blocking_tcp_client <host> <port> <message>\n"; return 1; } client c; - c.connect(argv[1], argv[2], boost::posix_time::seconds(10)); + c.connect(argv[1], argv[2], asio::chrono::seconds(10)); - boost::posix_time::ptime time_sent = - boost::posix_time::microsec_clock::universal_time(); + asio::chrono::steady_clock::time_point time_sent = + asio::chrono::steady_clock::now(); - c.write_line(argv[3], boost::posix_time::seconds(10)); + c.write_line(argv[3], asio::chrono::seconds(10)); for (;;) { - std::string line = c.read_line(boost::posix_time::seconds(10)); + std::string line = c.read_line(asio::chrono::seconds(10)); // Keep going until we get back the line that was sent. if (line == argv[3]) break; } - boost::posix_time::ptime time_received = - boost::posix_time::microsec_clock::universal_time(); + asio::chrono::steady_clock::time_point time_received = + asio::chrono::steady_clock::now(); std::cout << "Round trip time: "; - std::cout << (time_received - time_sent).total_microseconds(); + std::cout << asio::chrono::duration_cast< + asio::chrono::microseconds>( + time_received - time_sent).count(); std::cout << " microseconds\n"; } catch (std::exception& e) |