]>
git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/beast/example/websocket/server/fast/websocket_server_fast.cpp
2 // Copyright (c) 2016-2017 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, fast
14 //------------------------------------------------------------------------------
16 /* This server contains the following ports:
18 Synchronous <base port + 0>
19 Asynchronous <base port + 1>
20 Coroutine <base port + 2>
22 This program is optimized for the Autobahn|Testsuite
23 benchmarking and WebSocket compliants testing program.
26 https://github.com/crossbario/autobahn-testsuite
29 #include <boost/beast/core.hpp>
30 #include <boost/beast/http.hpp>
31 #include <boost/beast/version.hpp>
32 #include <boost/beast/websocket.hpp>
33 #include <boost/asio/bind_executor.hpp>
34 #include <boost/asio/spawn.hpp>
35 #include <boost/asio/strand.hpp>
36 #include <boost/asio/ip/tcp.hpp>
46 using tcp
= boost::asio::ip::tcp
; // from <boost/asio/ip/tcp.hpp>
47 namespace http
= boost::beast::http
; // from <boost/beast/http.hpp>
48 namespace websocket
= boost::beast::websocket
; // from <boost/beast/websocket.hpp>
50 //------------------------------------------------------------------------------
54 fail(boost::system::error_code ec
, char const* what
)
56 std::cerr
<< (std::string(what
) + ": " + ec
.message() + "\n");
59 // Adjust settings on the stream
60 template<class NextLayer
>
62 setup_stream(websocket::stream
<NextLayer
>& ws
)
64 // These values are tuned for Autobahn|Testsuite, and
65 // should also be generally helpful for increased performance.
67 websocket::permessage_deflate pmd
;
68 pmd
.client_enable
= true;
69 pmd
.server_enable
= true;
73 ws
.auto_fragment(false);
75 // Autobahn|Testsuite needs this
76 ws
.read_message_max(64 * 1024 * 1024);
79 //------------------------------------------------------------------------------
82 do_sync_session(tcp::socket
& socket
)
84 boost::system::error_code ec
;
86 websocket::stream
<tcp::socket
> ws
{std::move(socket
)};
90 [](websocket::response_type
& res
)
92 res
.set(http::field::server
,
93 "Boost.Beast/" + std::to_string(BOOST_BEAST_VERSION
) + "-Sync");
97 return fail(ec
, "accept");
101 boost::beast::multi_buffer buffer
;
104 if(ec
== websocket::error::closed
)
107 return fail(ec
, "read");
108 ws
.text(ws
.got_text());
109 ws
.write(buffer
.data(), ec
);
111 return fail(ec
, "write");
117 boost::asio::io_context
& ioc
,
118 tcp::endpoint endpoint
)
120 boost::system::error_code ec
;
121 tcp::acceptor acceptor
{ioc
, endpoint
};
124 tcp::socket socket
{ioc
};
126 acceptor
.accept(socket
, ec
);
128 return fail(ec
, "accept");
130 std::thread
{std::bind(
132 std::move(socket
))}.detach();
136 //------------------------------------------------------------------------------
138 // Echoes back all received WebSocket messages
139 class async_session
: public std::enable_shared_from_this
<async_session
>
141 websocket::stream
<tcp::socket
> ws_
;
143 boost::asio::io_context::executor_type
> strand_
;
144 boost::beast::multi_buffer buffer_
;
147 // Take ownership of the socket
149 async_session(tcp::socket socket
)
150 : ws_(std::move(socket
))
151 , strand_(ws_
.get_executor())
156 // Start the asynchronous operation
160 // Accept the websocket handshake
162 [](websocket::response_type
& res
)
164 res
.set(http::field::server
,
165 "Boost.Beast/" + std::to_string(BOOST_BEAST_VERSION
) + "-Async");
167 boost::asio::bind_executor(
170 &async_session::on_accept
,
172 std::placeholders::_1
)));
176 on_accept(boost::system::error_code ec
)
179 return fail(ec
, "accept");
188 // Read a message into our buffer
191 boost::asio::bind_executor(
194 &async_session::on_read
,
196 std::placeholders::_1
,
197 std::placeholders::_2
)));
202 boost::system::error_code ec
,
203 std::size_t bytes_transferred
)
205 boost::ignore_unused(bytes_transferred
);
207 // This indicates that the async_session was closed
208 if(ec
== websocket::error::closed
)
215 ws_
.text(ws_
.got_text());
218 boost::asio::bind_executor(
221 &async_session::on_write
,
223 std::placeholders::_1
,
224 std::placeholders::_2
)));
229 boost::system::error_code ec
,
230 std::size_t bytes_transferred
)
232 boost::ignore_unused(bytes_transferred
);
235 return fail(ec
, "write");
238 buffer_
.consume(buffer_
.size());
245 // Accepts incoming connections and launches the sessions
246 class async_listener
: public std::enable_shared_from_this
<async_listener
>
249 boost::asio::io_context::executor_type
> strand_
;
250 tcp::acceptor acceptor_
;
255 boost::asio::io_context
& ioc
,
256 tcp::endpoint endpoint
)
257 : strand_(ioc
.get_executor())
261 boost::system::error_code ec
;
264 acceptor_
.open(endpoint
.protocol(), ec
);
271 // Bind to the server address
272 acceptor_
.bind(endpoint
, ec
);
279 // Start listening for connections
281 boost::asio::socket_base::max_listen_connections
, ec
);
289 // Start accepting incoming connections
293 if(! acceptor_
.is_open())
301 acceptor_
.async_accept(
303 boost::asio::bind_executor(
306 &async_listener::on_accept
,
308 std::placeholders::_1
)));
312 on_accept(boost::system::error_code ec
)
320 // Create the async_session and run it
321 std::make_shared
<async_session
>(std::move(socket_
))->run();
324 // Accept another connection
329 //------------------------------------------------------------------------------
332 do_coro_session(tcp::socket
& socket
, boost::asio::yield_context yield
)
334 boost::system::error_code ec
;
336 websocket::stream
<tcp::socket
> ws
{std::move(socket
)};
340 [&](websocket::response_type
& res
)
342 res
.set(http::field::server
,
343 "Boost.Beast/" + std::to_string(BOOST_BEAST_VERSION
) + "-Coro");
347 return fail(ec
, "accept");
351 boost::beast::multi_buffer buffer
;
353 ws
.async_read(buffer
, yield
[ec
]);
354 if(ec
== websocket::error::closed
)
357 return fail(ec
, "read");
359 ws
.text(ws
.got_text());
360 ws
.async_write(buffer
.data(), yield
[ec
]);
362 return fail(ec
, "write");
368 boost::asio::io_context
& ioc
,
369 tcp::endpoint endpoint
,
370 boost::asio::yield_context yield
)
372 boost::system::error_code ec
;
374 tcp::acceptor
acceptor(ioc
);
375 acceptor
.open(endpoint
.protocol(), ec
);
377 return fail(ec
, "open");
379 acceptor
.bind(endpoint
, ec
);
381 return fail(ec
, "bind");
383 acceptor
.listen(boost::asio::socket_base::max_listen_connections
, ec
);
385 return fail(ec
, "listen");
389 tcp::socket
socket(ioc
);
391 acceptor
.async_accept(socket
, yield
[ec
]);
399 acceptor
.get_executor().context(),
403 std::placeholders::_1
));
407 //------------------------------------------------------------------------------
409 int main(int argc
, char* argv
[])
411 // Check command line arguments.
415 "Usage: websocket-server-fast <address> <starting-port> <threads>\n" <<
417 " websocket-server-fast 0.0.0.0 8080 1\n"
419 " starting-port+0 for synchronous,\n"
420 " starting-port+1 for asynchronous,\n"
421 " starting-port+2 for coroutine.\n";
424 auto const address
= boost::asio::ip::make_address(argv
[1]);
425 auto const port
= static_cast<unsigned short>(std::atoi(argv
[2]));
426 auto const threads
= std::max
<int>(1, std::atoi(argv
[3]));
428 // The io_context is required for all I/O
429 boost::asio::io_context ioc
{threads
};
432 std::thread(std::bind(
437 static_cast<unsigned short>(port
+ 0u)}
441 std::make_shared
<async_listener
>(
445 static_cast<unsigned short>(port
+ 1u)})->run();
448 boost::asio::spawn(ioc
,
454 static_cast<unsigned short>(port
+ 2u)},
455 std::placeholders::_1
));
457 // Run the I/O service on the requested number of threads
458 std::vector
<std::thread
> v
;
459 v
.reserve(threads
- 1);
460 for(auto i
= threads
- 1; i
> 0; --i
)