2 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 // Official repository: https://github.com/boostorg/beast
10 //------------------------------------------------------------------------------
12 // Example: WebSocket client, asynchronous
14 //------------------------------------------------------------------------------
16 #include <boost/beast/core.hpp>
17 #include <boost/beast/websocket.hpp>
18 #include <boost/asio/strand.hpp>
25 namespace beast
= boost::beast
; // from <boost/beast.hpp>
26 namespace http
= beast::http
; // from <boost/beast/http.hpp>
27 namespace websocket
= beast::websocket
; // from <boost/beast/websocket.hpp>
28 namespace net
= boost::asio
; // from <boost/asio.hpp>
29 using tcp
= boost::asio::ip::tcp
; // from <boost/asio/ip/tcp.hpp>
31 //------------------------------------------------------------------------------
35 fail(beast::error_code ec
, char const* what
)
37 std::cerr
<< what
<< ": " << ec
.message() << "\n";
40 // Sends a WebSocket message and prints the response
41 class session
: public std::enable_shared_from_this
<session
>
43 tcp::resolver resolver_
;
44 websocket::stream
<beast::tcp_stream
> ws_
;
45 beast::flat_buffer buffer_
;
50 // Resolver and socket require an io_context
52 session(net::io_context
& ioc
)
53 : resolver_(net::make_strand(ioc
))
54 , ws_(net::make_strand(ioc
))
58 // Start the asynchronous operation
65 // Save these for later
69 // Look up the domain name
70 resolver_
.async_resolve(
73 beast::bind_front_handler(
81 tcp::resolver::results_type results
)
84 return fail(ec
, "resolve");
86 // Set the timeout for the operation
87 beast::get_lowest_layer(ws_
).expires_after(std::chrono::seconds(30));
89 // Make the connection on the IP address we get from a lookup
90 beast::get_lowest_layer(ws_
).async_connect(
92 beast::bind_front_handler(
98 on_connect(beast::error_code ec
, tcp::resolver::results_type::endpoint_type
)
101 return fail(ec
, "connect");
103 // Turn off the timeout on the tcp_stream, because
104 // the websocket stream has its own timeout system.
105 beast::get_lowest_layer(ws_
).expires_never();
107 // Set suggested timeout settings for the websocket
109 websocket::stream_base::timeout::suggested(
110 beast::role_type::client
));
112 // Set a decorator to change the User-Agent of the handshake
113 ws_
.set_option(websocket::stream_base::decorator(
114 [](websocket::request_type
& req
)
116 req
.set(http::field::user_agent
,
117 std::string(BOOST_BEAST_VERSION_STRING
) +
118 " websocket-client-async");
121 // Perform the websocket handshake
122 ws_
.async_handshake(host_
, "/",
123 beast::bind_front_handler(
124 &session::on_handshake
,
125 shared_from_this()));
129 on_handshake(beast::error_code ec
)
132 return fail(ec
, "handshake");
137 beast::bind_front_handler(
139 shared_from_this()));
144 beast::error_code ec
,
145 std::size_t bytes_transferred
)
147 boost::ignore_unused(bytes_transferred
);
150 return fail(ec
, "write");
152 // Read a message into our buffer
155 beast::bind_front_handler(
157 shared_from_this()));
162 beast::error_code ec
,
163 std::size_t bytes_transferred
)
165 boost::ignore_unused(bytes_transferred
);
168 return fail(ec
, "read");
170 // Close the WebSocket connection
171 ws_
.async_close(websocket::close_code::normal
,
172 beast::bind_front_handler(
174 shared_from_this()));
178 on_close(beast::error_code ec
)
181 return fail(ec
, "close");
183 // If we get here then the connection is closed gracefully
185 // The make_printable() function helps print a ConstBufferSequence
186 std::cout
<< beast::make_printable(buffer_
.data()) << std::endl
;
190 //------------------------------------------------------------------------------
192 int main(int argc
, char** argv
)
194 // Check command line arguments.
198 "Usage: websocket-client-async <host> <port> <text>\n" <<
200 " websocket-client-async echo.websocket.org 80 \"Hello, world!\"\n";
203 auto const host
= argv
[1];
204 auto const port
= argv
[2];
205 auto const text
= argv
[3];
207 // The io_context is required for all I/O
210 // Launch the asynchronous operation
211 std::make_shared
<session
>(ioc
)->run(host
, port
, text
);
213 // Run the I/O service. The call will return when
214 // the socket is closed.