]>
git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/asio/example/cpp03/timeouts/blocking_tcp_client.cpp
2 // blocking_tcp_client.cpp
3 // ~~~~~~~~~~~~~~~~~~~~~~~
5 // Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
11 #include <boost/asio/connect.hpp>
12 #include <boost/asio/deadline_timer.hpp>
13 #include <boost/asio/io_context.hpp>
14 #include <boost/asio/ip/tcp.hpp>
15 #include <boost/asio/read_until.hpp>
16 #include <boost/asio/streambuf.hpp>
17 #include <boost/system/system_error.hpp>
18 #include <boost/asio/write.hpp>
22 #include <boost/lambda/bind.hpp>
23 #include <boost/lambda/lambda.hpp>
25 using boost::asio::deadline_timer
;
26 using boost::asio::ip::tcp
;
27 using boost::lambda::bind
;
28 using boost::lambda::var
;
29 using boost::lambda::_1
;
31 //----------------------------------------------------------------------
34 // This class manages socket timeouts by applying the concept of a deadline.
35 // Each asynchronous operation is given a deadline by which it must complete.
36 // Deadlines are enforced by an "actor" that persists for the lifetime of the
41 // | check_deadline |<---+
43 // +----------------+ | async_wait()
47 // If the actor determines that the deadline has expired, the socket is closed
48 // and any outstanding operations are consequently cancelled. The socket
49 // operations themselves use boost::lambda function objects as completion
50 // handlers. For a given socket operation, the client object runs the
51 // io_context to block thread execution until the actor completes.
57 : socket_(io_context_
),
58 deadline_(io_context_
)
60 // No deadline is required until the first socket operation is started. We
61 // set the deadline to positive infinity so that the actor takes no action
62 // until a specific deadline is set.
63 deadline_
.expires_at(boost::posix_time::pos_infin
);
65 // Start the persistent actor that checks for deadline expiry.
69 void connect(const std::string
& host
, const std::string
& service
,
70 boost::posix_time::time_duration timeout
)
72 // Resolve the host name and service to a list of endpoints.
73 tcp::resolver::results_type endpoints
=
74 tcp::resolver(io_context_
).resolve(host
, service
);
76 // Set a deadline for the asynchronous operation. As a host name may
77 // resolve to multiple endpoints, this function uses the composed operation
78 // async_connect. The deadline applies to the entire operation, rather than
79 // individual connection attempts.
80 deadline_
.expires_from_now(timeout
);
82 // Set up the variable that receives the result of the asynchronous
83 // operation. The error code is set to would_block to signal that the
84 // operation is incomplete. Asio guarantees that its asynchronous
85 // operations will never fail with would_block, so any other value in
86 // ec indicates completion.
87 boost::system::error_code ec
= boost::asio::error::would_block
;
89 // Start the asynchronous operation itself. The boost::lambda function
90 // object is used as a callback and will update the ec variable when the
91 // operation completes. The blocking_udp_client.cpp example shows how you
92 // can use boost::bind rather than boost::lambda.
93 boost::asio::async_connect(socket_
, endpoints
, var(ec
) = _1
);
95 // Block until the asynchronous operation has completed.
96 do io_context_
.run_one(); while (ec
== boost::asio::error::would_block
);
98 // Determine whether a connection was successfully established. The
99 // deadline actor may have had a chance to run and close our socket, even
100 // though the connect operation notionally succeeded. Therefore we must
101 // check whether the socket is still open before deciding if we succeeded
103 if (ec
|| !socket_
.is_open())
104 throw boost::system::system_error(
105 ec
? ec
: boost::asio::error::operation_aborted
);
108 std::string
read_line(boost::posix_time::time_duration timeout
)
110 // Set a deadline for the asynchronous operation. Since this function uses
111 // a composed operation (async_read_until), the deadline applies to the
112 // entire operation, rather than individual reads from the socket.
113 deadline_
.expires_from_now(timeout
);
115 // Set up the variable that receives the result of the asynchronous
116 // operation. The error code is set to would_block to signal that the
117 // operation is incomplete. Asio guarantees that its asynchronous
118 // operations will never fail with would_block, so any other value in
119 // ec indicates completion.
120 boost::system::error_code ec
= boost::asio::error::would_block
;
122 // Start the asynchronous operation itself. The boost::lambda function
123 // object is used as a callback and will update the ec variable when the
124 // operation completes. The blocking_udp_client.cpp example shows how you
125 // can use boost::bind rather than boost::lambda.
126 boost::asio::async_read_until(socket_
, input_buffer_
, '\n', var(ec
) = _1
);
128 // Block until the asynchronous operation has completed.
129 do io_context_
.run_one(); while (ec
== boost::asio::error::would_block
);
132 throw boost::system::system_error(ec
);
135 std::istream
is(&input_buffer_
);
136 std::getline(is
, line
);
140 void write_line(const std::string
& line
,
141 boost::posix_time::time_duration timeout
)
143 std::string data
= line
+ "\n";
145 // Set a deadline for the asynchronous operation. Since this function uses
146 // a composed operation (async_write), the deadline applies to the entire
147 // operation, rather than individual writes to the socket.
148 deadline_
.expires_from_now(timeout
);
150 // Set up the variable that receives the result of the asynchronous
151 // operation. The error code is set to would_block to signal that the
152 // operation is incomplete. Asio guarantees that its asynchronous
153 // operations will never fail with would_block, so any other value in
154 // ec indicates completion.
155 boost::system::error_code ec
= boost::asio::error::would_block
;
157 // Start the asynchronous operation itself. The boost::lambda function
158 // object is used as a callback and will update the ec variable when the
159 // operation completes. The blocking_udp_client.cpp example shows how you
160 // can use boost::bind rather than boost::lambda.
161 boost::asio::async_write(socket_
, boost::asio::buffer(data
), var(ec
) = _1
);
163 // Block until the asynchronous operation has completed.
164 do io_context_
.run_one(); while (ec
== boost::asio::error::would_block
);
167 throw boost::system::system_error(ec
);
171 void check_deadline()
173 // Check whether the deadline has passed. We compare the deadline against
174 // the current time since a new asynchronous operation may have moved the
175 // deadline before this actor had a chance to run.
176 if (deadline_
.expires_at() <= deadline_timer::traits_type::now())
178 // The deadline has passed. The socket is closed so that any outstanding
179 // asynchronous operations are cancelled. This allows the blocked
180 // connect(), read_line() or write_line() functions to return.
181 boost::system::error_code ignored_ec
;
182 socket_
.close(ignored_ec
);
184 // There is no longer an active deadline. The expiry is set to positive
185 // infinity so that the actor takes no action until a new deadline is set.
186 deadline_
.expires_at(boost::posix_time::pos_infin
);
189 // Put the actor back to sleep.
190 deadline_
.async_wait(bind(&client::check_deadline
, this));
193 boost::asio::io_context io_context_
;
195 deadline_timer deadline_
;
196 boost::asio::streambuf input_buffer_
;
199 //----------------------------------------------------------------------
201 int main(int argc
, char* argv
[])
207 std::cerr
<< "Usage: blocking_tcp <host> <port> <message>\n";
212 c
.connect(argv
[1], argv
[2], boost::posix_time::seconds(10));
214 boost::posix_time::ptime time_sent
=
215 boost::posix_time::microsec_clock::universal_time();
217 c
.write_line(argv
[3], boost::posix_time::seconds(10));
221 std::string line
= c
.read_line(boost::posix_time::seconds(10));
223 // Keep going until we get back the line that was sent.
228 boost::posix_time::ptime time_received
=
229 boost::posix_time::microsec_clock::universal_time();
231 std::cout
<< "Round trip time: ";
232 std::cout
<< (time_received
- time_sent
).total_microseconds();
233 std::cout
<< " microseconds\n";
235 catch (std::exception
& e
)
237 std::cerr
<< "Exception: " << e
.what() << "\n";