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 server, coroutine
14 //------------------------------------------------------------------------------
16 #include <boost/beast/core.hpp>
17 #include <boost/beast/websocket.hpp>
18 #include <boost/asio/spawn.hpp>
28 namespace beast
= boost::beast
; // from <boost/beast.hpp>
29 namespace http
= beast::http
; // from <boost/beast/http.hpp>
30 namespace websocket
= beast::websocket
; // from <boost/beast/websocket.hpp>
31 namespace net
= boost::asio
; // from <boost/asio.hpp>
32 using tcp
= boost::asio::ip::tcp
; // from <boost/asio/ip/tcp.hpp>
34 //------------------------------------------------------------------------------
38 fail(beast::error_code ec
, char const* what
)
40 std::cerr
<< what
<< ": " << ec
.message() << "\n";
43 // Echoes back all received WebSocket messages
46 websocket::stream
<beast::tcp_stream
>& ws
,
47 net::yield_context yield
)
51 // Set suggested timeout settings for the websocket
53 websocket::stream_base::timeout::suggested(
54 beast::role_type::server
));
56 // Set a decorator to change the Server of the handshake
57 ws
.set_option(websocket::stream_base::decorator(
58 [](websocket::response_type
& res
)
60 res
.set(http::field::server
,
61 std::string(BOOST_BEAST_VERSION_STRING
) +
62 " websocket-server-coro");
65 // Accept the websocket handshake
66 ws
.async_accept(yield
[ec
]);
68 return fail(ec
, "accept");
72 // This buffer will hold the incoming message
73 beast::flat_buffer buffer
;
76 ws
.async_read(buffer
, yield
[ec
]);
78 // This indicates that the session was closed
79 if(ec
== websocket::error::closed
)
83 return fail(ec
, "read");
85 // Echo the message back
86 ws
.text(ws
.got_text());
87 ws
.async_write(buffer
.data(), yield
[ec
]);
89 return fail(ec
, "write");
93 //------------------------------------------------------------------------------
95 // Accepts incoming connections and launches the sessions
99 tcp::endpoint endpoint
,
100 net::yield_context yield
)
102 beast::error_code ec
;
105 tcp::acceptor
acceptor(ioc
);
106 acceptor
.open(endpoint
.protocol(), ec
);
108 return fail(ec
, "open");
110 // Allow address reuse
111 acceptor
.set_option(net::socket_base::reuse_address(true), ec
);
113 return fail(ec
, "set_option");
115 // Bind to the server address
116 acceptor
.bind(endpoint
, ec
);
118 return fail(ec
, "bind");
120 // Start listening for connections
121 acceptor
.listen(net::socket_base::max_listen_connections
, ec
);
123 return fail(ec
, "listen");
127 tcp::socket
socket(ioc
);
128 acceptor
.async_accept(socket
, yield
[ec
]);
133 acceptor
.get_executor(),
137 beast::tcp_stream
>(std::move(socket
)),
138 std::placeholders::_1
));
142 int main(int argc
, char* argv
[])
144 // Check command line arguments.
148 "Usage: websocket-server-coro <address> <port> <threads>\n" <<
150 " websocket-server-coro 0.0.0.0 8080 1\n";
153 auto const address
= net::ip::make_address(argv
[1]);
154 auto const port
= static_cast<unsigned short>(std::atoi(argv
[2]));
155 auto const threads
= std::max
<int>(1, std::atoi(argv
[3]));
157 // The io_context is required for all I/O
158 net::io_context
ioc(threads
);
160 // Spawn a listening port
161 boost::asio::spawn(ioc
,
165 tcp::endpoint
{address
, port
},
166 std::placeholders::_1
));
168 // Run the I/O service on the requested number of threads
169 std::vector
<std::thread
> v
;
170 v
.reserve(threads
- 1);
171 for(auto i
= threads
- 1; i
> 0; --i
)