mirror of
https://github.com/boostorg/beast.git
synced 2025-07-30 04:47:29 +02:00
Use tcp_stream in WebSocket server examples
This commit is contained in:
@ -5,6 +5,7 @@ Version 213:
|
||||
* Use timeouts in HTTP server examples
|
||||
* Use timeouts in HTTP client examples
|
||||
* Use tcp_stream in WebSocket client examples
|
||||
* Use tcp_stream in WebSocket server examples
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
@ -18,10 +18,8 @@
|
||||
#include <boost/beast/core.hpp>
|
||||
#include <boost/beast/websocket.hpp>
|
||||
#include <boost/beast/websocket/ssl.hpp>
|
||||
#include <boost/asio/bind_executor.hpp>
|
||||
#include <boost/beast/_experimental/core/ssl_stream.hpp>
|
||||
#include <boost/asio/strand.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/asio/ssl/stream.hpp>
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <functional>
|
||||
@ -50,18 +48,14 @@ fail(beast::error_code ec, char const* what)
|
||||
// Echoes back all received WebSocket messages
|
||||
class session : public std::enable_shared_from_this<session>
|
||||
{
|
||||
tcp::socket socket_;
|
||||
websocket::stream<ssl::stream<tcp::socket&>> ws_;
|
||||
net::strand<
|
||||
net::io_context::executor_type> strand_;
|
||||
websocket::stream<beast::ssl_stream<
|
||||
beast::tcp_stream<net::io_context::strand>>> ws_;
|
||||
beast::multi_buffer buffer_;
|
||||
|
||||
public:
|
||||
// Take ownership of the socket
|
||||
session(tcp::socket socket, ssl::context& ctx)
|
||||
: socket_(std::move(socket))
|
||||
, ws_(socket_, ctx)
|
||||
, strand_(ws_.get_executor())
|
||||
: ws_(std::move(socket), ctx)
|
||||
{
|
||||
}
|
||||
|
||||
@ -69,15 +63,16 @@ public:
|
||||
void
|
||||
run()
|
||||
{
|
||||
// Set the timeout.
|
||||
beast::get_lowest_layer(ws_).expires_after(std::chrono::seconds(30));
|
||||
|
||||
// Perform the SSL handshake
|
||||
ws_.next_layer().async_handshake(
|
||||
ssl::stream_base::server,
|
||||
net::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&session::on_handshake,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
std::bind(
|
||||
&session::on_handshake,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1));
|
||||
}
|
||||
|
||||
void
|
||||
@ -88,12 +83,10 @@ public:
|
||||
|
||||
// Accept the websocket handshake
|
||||
ws_.async_accept(
|
||||
net::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&session::on_accept,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
std::bind(
|
||||
&session::on_accept,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1));
|
||||
}
|
||||
|
||||
void
|
||||
@ -112,13 +105,11 @@ public:
|
||||
// Read a message into our buffer
|
||||
ws_.async_read(
|
||||
buffer_,
|
||||
net::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&session::on_read,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
std::bind(
|
||||
&session::on_read,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
}
|
||||
|
||||
void
|
||||
@ -139,13 +130,11 @@ public:
|
||||
ws_.text(ws_.got_text());
|
||||
ws_.async_write(
|
||||
buffer_.data(),
|
||||
net::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&session::on_write,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
std::bind(
|
||||
&session::on_write,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
}
|
||||
|
||||
void
|
||||
@ -173,7 +162,6 @@ class listener : public std::enable_shared_from_this<listener>
|
||||
{
|
||||
ssl::context& ctx_;
|
||||
tcp::acceptor acceptor_;
|
||||
tcp::socket socket_;
|
||||
|
||||
public:
|
||||
listener(
|
||||
@ -182,7 +170,6 @@ public:
|
||||
tcp::endpoint endpoint)
|
||||
: ctx_(ctx)
|
||||
, acceptor_(ioc)
|
||||
, socket_(ioc)
|
||||
{
|
||||
beast::error_code ec;
|
||||
|
||||
@ -233,15 +220,15 @@ public:
|
||||
do_accept()
|
||||
{
|
||||
acceptor_.async_accept(
|
||||
socket_,
|
||||
std::bind(
|
||||
&listener::on_accept,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1));
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
}
|
||||
|
||||
void
|
||||
on_accept(beast::error_code ec)
|
||||
on_accept(beast::error_code ec, tcp::socket socket)
|
||||
{
|
||||
if(ec)
|
||||
{
|
||||
@ -250,7 +237,7 @@ public:
|
||||
else
|
||||
{
|
||||
// Create the session and run it
|
||||
std::make_shared<session>(std::move(socket_), ctx_)->run();
|
||||
std::make_shared<session>(std::move(socket), ctx_)->run();
|
||||
}
|
||||
|
||||
// Accept another connection
|
||||
|
@ -15,9 +15,7 @@
|
||||
|
||||
#include <boost/beast/core.hpp>
|
||||
#include <boost/beast/websocket.hpp>
|
||||
#include <boost/asio/bind_executor.hpp>
|
||||
#include <boost/asio/strand.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <functional>
|
||||
@ -45,9 +43,7 @@ fail(beast::error_code ec, char const* what)
|
||||
// Echoes back all received WebSocket messages
|
||||
class session : public std::enable_shared_from_this<session>
|
||||
{
|
||||
websocket::stream<tcp::socket> ws_;
|
||||
net::strand<
|
||||
net::io_context::executor_type> strand_;
|
||||
websocket::stream<beast::tcp_stream<net::io_context::strand>> ws_;
|
||||
beast::multi_buffer buffer_;
|
||||
|
||||
public:
|
||||
@ -55,7 +51,6 @@ public:
|
||||
explicit
|
||||
session(tcp::socket socket)
|
||||
: ws_(std::move(socket))
|
||||
, strand_(ws_.get_executor())
|
||||
{
|
||||
}
|
||||
|
||||
@ -65,12 +60,10 @@ public:
|
||||
{
|
||||
// Accept the websocket handshake
|
||||
ws_.async_accept(
|
||||
net::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&session::on_accept,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
std::bind(
|
||||
&session::on_accept,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1));
|
||||
}
|
||||
|
||||
void
|
||||
@ -89,13 +82,11 @@ public:
|
||||
// Read a message into our buffer
|
||||
ws_.async_read(
|
||||
buffer_,
|
||||
net::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&session::on_read,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
std::bind(
|
||||
&session::on_read,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
}
|
||||
|
||||
void
|
||||
@ -116,13 +107,11 @@ public:
|
||||
ws_.text(ws_.got_text());
|
||||
ws_.async_write(
|
||||
buffer_.data(),
|
||||
net::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&session::on_write,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
std::bind(
|
||||
&session::on_write,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
}
|
||||
|
||||
void
|
||||
@ -149,14 +138,12 @@ public:
|
||||
class listener : public std::enable_shared_from_this<listener>
|
||||
{
|
||||
tcp::acceptor acceptor_;
|
||||
tcp::socket socket_;
|
||||
|
||||
public:
|
||||
listener(
|
||||
net::io_context& ioc,
|
||||
tcp::endpoint endpoint)
|
||||
: acceptor_(ioc)
|
||||
, socket_(ioc)
|
||||
{
|
||||
beast::error_code ec;
|
||||
|
||||
@ -207,15 +194,15 @@ public:
|
||||
do_accept()
|
||||
{
|
||||
acceptor_.async_accept(
|
||||
socket_,
|
||||
std::bind(
|
||||
&listener::on_accept,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1));
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
}
|
||||
|
||||
void
|
||||
on_accept(beast::error_code ec)
|
||||
on_accept(beast::error_code ec, tcp::socket socket)
|
||||
{
|
||||
if(ec)
|
||||
{
|
||||
@ -224,7 +211,7 @@ public:
|
||||
else
|
||||
{
|
||||
// Create the session and run it
|
||||
std::make_shared<session>(std::move(socket_))->run();
|
||||
std::make_shared<session>(std::move(socket))->run();
|
||||
}
|
||||
|
||||
// Accept another connection
|
||||
|
@ -190,11 +190,10 @@ handle_request(
|
||||
|
||||
http_session::
|
||||
http_session(
|
||||
tcp::socket socket,
|
||||
tcp::socket&& socket,
|
||||
boost::shared_ptr<shared_state> const& state)
|
||||
: socket_(std::move(socket))
|
||||
: stream_(std::move(socket))
|
||||
, state_(state)
|
||||
, strand_(socket_.get_executor())
|
||||
{
|
||||
}
|
||||
|
||||
@ -202,14 +201,16 @@ void
|
||||
http_session::
|
||||
run()
|
||||
{
|
||||
// Set the timeout.
|
||||
stream_.expires_after(std::chrono::seconds(30));
|
||||
|
||||
// Read a request
|
||||
http::async_read(socket_, buffer_, req_,
|
||||
net::bind_executor(strand_,
|
||||
std::bind(
|
||||
&http_session::on_read,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
http::async_read(stream_, buffer_, req_,
|
||||
std::bind(
|
||||
&http_session::on_read,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
}
|
||||
|
||||
// Report a failure
|
||||
@ -239,13 +240,12 @@ operator()(http::message<isRequest, Body, Fields>&& msg) const
|
||||
// Write the response
|
||||
auto self = self_.shared_from_this();
|
||||
http::async_write(
|
||||
self_.socket_,
|
||||
self_.stream_,
|
||||
*sp,
|
||||
net::bind_executor(self_.strand_,
|
||||
[self, sp](beast::error_code ec, std::size_t bytes)
|
||||
{
|
||||
self->on_write(ec, bytes, sp->need_eof());
|
||||
}));
|
||||
[self, sp](beast::error_code ec, std::size_t bytes)
|
||||
{
|
||||
self->on_write(ec, bytes, sp->need_eof());
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
@ -255,7 +255,7 @@ on_read(beast::error_code ec, std::size_t)
|
||||
// This means they closed the connection
|
||||
if(ec == http::error::end_of_stream)
|
||||
{
|
||||
socket_.shutdown(tcp::socket::shutdown_send, ec);
|
||||
stream_.socket().shutdown(tcp::socket::shutdown_send, ec);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -268,7 +268,8 @@ on_read(beast::error_code ec, std::size_t)
|
||||
{
|
||||
// Create a WebSocket session by transferring the socket
|
||||
boost::make_shared<websocket_session>(
|
||||
std::move(socket_), state_)->run(std::move(req_));
|
||||
std::move(stream_.release_socket()),
|
||||
state_)->run(std::move(req_));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -292,23 +293,21 @@ on_read(beast::error_code ec, std::size_t)
|
||||
#if 0
|
||||
// NOTE This causes an ICE in gcc 7.3
|
||||
// Write the response
|
||||
http::async_write(this->socket_, *sp,
|
||||
net::bind_executor(strand_,
|
||||
[self = shared_from_this(), sp](
|
||||
beast::error_code ec, std::size_t bytes)
|
||||
{
|
||||
self->on_write(ec, bytes, sp->need_eof());
|
||||
}));
|
||||
http::async_write(this->stream_, *sp,
|
||||
[self = shared_from_this(), sp](
|
||||
beast::error_code ec, std::size_t bytes)
|
||||
{
|
||||
self->on_write(ec, bytes, sp->need_eof());
|
||||
});
|
||||
#else
|
||||
// Write the response
|
||||
auto self = shared_from_this();
|
||||
http::async_write(this->socket_, *sp,
|
||||
net::bind_executor(strand_,
|
||||
[self, sp](
|
||||
beast::error_code ec, std::size_t bytes)
|
||||
{
|
||||
self->on_write(ec, bytes, sp->need_eof());
|
||||
}));
|
||||
http::async_write(stream_, *sp,
|
||||
[self, sp](
|
||||
beast::error_code ec, std::size_t bytes)
|
||||
{
|
||||
self->on_write(ec, bytes, sp->need_eof());
|
||||
});
|
||||
#endif
|
||||
});
|
||||
#else
|
||||
@ -336,7 +335,7 @@ on_write(beast::error_code ec, std::size_t, bool close)
|
||||
{
|
||||
// This means we should close the connection, usually because
|
||||
// the response indicated the "Connection: close" semantic.
|
||||
socket_.shutdown(tcp::socket::shutdown_send, ec);
|
||||
stream_.socket().shutdown(tcp::socket::shutdown_send, ec);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -344,8 +343,11 @@ on_write(beast::error_code ec, std::size_t, bool close)
|
||||
// otherwise the read behavior is undefined.
|
||||
req_ = {};
|
||||
|
||||
// Set the timeout.
|
||||
stream_.expires_after(std::chrono::seconds(30));
|
||||
|
||||
// Read another request
|
||||
http::async_read(socket_, buffer_, req_,
|
||||
http::async_read(stream_, buffer_, req_,
|
||||
std::bind(
|
||||
&http_session::on_read,
|
||||
shared_from_this(),
|
||||
|
@ -21,11 +21,10 @@
|
||||
*/
|
||||
class http_session : public boost::enable_shared_from_this<http_session>
|
||||
{
|
||||
tcp::socket socket_;
|
||||
beast::tcp_stream<net::io_context::strand> stream_;
|
||||
beast::flat_buffer buffer_;
|
||||
boost::shared_ptr<shared_state> state_;
|
||||
http::request<http::string_body> req_;
|
||||
net::strand<net::io_context::executor_type> strand_;
|
||||
|
||||
struct send_lambda
|
||||
{
|
||||
@ -48,7 +47,7 @@ class http_session : public boost::enable_shared_from_this<http_session>
|
||||
|
||||
public:
|
||||
http_session(
|
||||
tcp::socket socket,
|
||||
tcp::socket&& socket,
|
||||
boost::shared_ptr<shared_state> const& state);
|
||||
|
||||
void run();
|
||||
|
@ -17,7 +17,6 @@ listener(
|
||||
tcp::endpoint endpoint,
|
||||
boost::shared_ptr<shared_state> const& state)
|
||||
: acceptor_(ioc)
|
||||
, socket_(ioc)
|
||||
, state_(state)
|
||||
{
|
||||
beast::error_code ec;
|
||||
@ -62,11 +61,11 @@ run()
|
||||
{
|
||||
// Start accepting a connection
|
||||
acceptor_.async_accept(
|
||||
socket_,
|
||||
std::bind(
|
||||
&listener::on_accept,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1));
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
}
|
||||
|
||||
// Report a failure
|
||||
@ -83,21 +82,21 @@ fail(beast::error_code ec, char const* what)
|
||||
// Handle a connection
|
||||
void
|
||||
listener::
|
||||
on_accept(beast::error_code ec)
|
||||
on_accept(beast::error_code ec, tcp::socket socket)
|
||||
{
|
||||
if(ec)
|
||||
return fail(ec, "accept");
|
||||
else
|
||||
// Launch a new session for this connection
|
||||
boost::make_shared<http_session>(
|
||||
std::move(socket_),
|
||||
std::move(socket),
|
||||
state_)->run();
|
||||
|
||||
// Accept another connection
|
||||
acceptor_.async_accept(
|
||||
socket_,
|
||||
std::bind(
|
||||
&listener::on_accept,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1));
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
}
|
||||
|
@ -23,11 +23,10 @@ class shared_state;
|
||||
class listener : public boost::enable_shared_from_this<listener>
|
||||
{
|
||||
tcp::acceptor acceptor_;
|
||||
tcp::socket socket_;
|
||||
boost::shared_ptr<shared_state> state_;
|
||||
|
||||
void fail(beast::error_code ec, char const* what);
|
||||
void on_accept(beast::error_code ec);
|
||||
void on_accept(beast::error_code ec, tcp::socket socket);
|
||||
|
||||
public:
|
||||
listener(
|
||||
|
@ -35,7 +35,7 @@ main(int argc, char* argv[])
|
||||
std::cerr <<
|
||||
"Usage: websocket-chat-multi <address> <port> <doc_root> <threads>\n" <<
|
||||
"Example:\n" <<
|
||||
" websocket-chat-server 0.0.0.0 8080 .\n";
|
||||
" websocket-chat-server 0.0.0.0 8080 . 5\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
auto address = net::ip::make_address(argv[1]);
|
||||
|
@ -12,11 +12,10 @@
|
||||
|
||||
websocket_session::
|
||||
websocket_session(
|
||||
tcp::socket socket,
|
||||
tcp::socket&& socket,
|
||||
boost::shared_ptr<shared_state> const& state)
|
||||
: ws_(std::move(socket))
|
||||
, state_(state)
|
||||
, strand_(ws_.get_executor())
|
||||
{
|
||||
}
|
||||
|
||||
@ -53,12 +52,11 @@ on_accept(beast::error_code ec)
|
||||
// Read a message
|
||||
ws_.async_read(
|
||||
buffer_,
|
||||
net::bind_executor(strand_,
|
||||
std::bind(
|
||||
&websocket_session::on_read,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
std::bind(
|
||||
&websocket_session::on_read,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
}
|
||||
|
||||
void
|
||||
@ -78,12 +76,11 @@ on_read(beast::error_code ec, std::size_t)
|
||||
// Read another message
|
||||
ws_.async_read(
|
||||
buffer_,
|
||||
net::bind_executor(strand_,
|
||||
std::bind(
|
||||
&websocket_session::on_read,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
std::bind(
|
||||
&websocket_session::on_read,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
}
|
||||
|
||||
void
|
||||
@ -93,13 +90,13 @@ send(boost::shared_ptr<std::string const> const& ss)
|
||||
// Get on the strand if we aren't already,
|
||||
// otherwise we will concurrently access
|
||||
// objects which are not thread-safe.
|
||||
if(! strand_.running_in_this_thread())
|
||||
if(! ws_.get_executor().running_in_this_thread())
|
||||
return net::post(
|
||||
net::bind_executor(strand_,
|
||||
std::bind(
|
||||
&websocket_session::send,
|
||||
shared_from_this(),
|
||||
ss)));
|
||||
ws_.get_executor(),
|
||||
std::bind(
|
||||
&websocket_session::send,
|
||||
shared_from_this(),
|
||||
ss));
|
||||
|
||||
// Always add to queue
|
||||
queue_.push_back(ss);
|
||||
@ -111,12 +108,11 @@ send(boost::shared_ptr<std::string const> const& ss)
|
||||
// We are not currently writing, so send this immediately
|
||||
ws_.async_write(
|
||||
net::buffer(*queue_.front()),
|
||||
net::bind_executor(strand_,
|
||||
std::bind(
|
||||
&websocket_session::on_write,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
std::bind(
|
||||
&websocket_session::on_write,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
}
|
||||
|
||||
void
|
||||
@ -134,10 +130,9 @@ on_write(beast::error_code ec, std::size_t)
|
||||
if(! queue_.empty())
|
||||
ws_.async_write(
|
||||
net::buffer(*queue_.front()),
|
||||
net::bind_executor(strand_,
|
||||
std::bind(
|
||||
&websocket_session::on_write,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
std::bind(
|
||||
&websocket_session::on_write,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
}
|
||||
|
@ -27,10 +27,9 @@ class shared_state;
|
||||
class websocket_session : public boost::enable_shared_from_this<websocket_session>
|
||||
{
|
||||
beast::flat_buffer buffer_;
|
||||
websocket::stream<tcp::socket> ws_;
|
||||
websocket::stream<beast::tcp_stream<net::io_context::strand>> ws_;
|
||||
boost::shared_ptr<shared_state> state_;
|
||||
std::vector<boost::shared_ptr<std::string const>> queue_;
|
||||
net::strand<net::io_context::executor_type> strand_;
|
||||
|
||||
void fail(beast::error_code ec, char const* what);
|
||||
void on_accept(beast::error_code ec);
|
||||
@ -39,7 +38,7 @@ class websocket_session : public boost::enable_shared_from_this<websocket_sessio
|
||||
|
||||
public:
|
||||
websocket_session(
|
||||
tcp::socket socket,
|
||||
tcp::socket&& socket,
|
||||
boost::shared_ptr<shared_state> const& state);
|
||||
|
||||
~websocket_session();
|
||||
|
@ -18,9 +18,8 @@
|
||||
#include <boost/beast/core.hpp>
|
||||
#include <boost/beast/websocket.hpp>
|
||||
#include <boost/beast/websocket/ssl.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/beast/_experimental/core/ssl_stream.hpp>
|
||||
#include <boost/asio/spawn.hpp>
|
||||
#include <boost/asio/ssl/stream.hpp>
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <functional>
|
||||
@ -39,6 +38,11 @@ using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// The type of websocket stream to use
|
||||
// Stackful coroutines are already stranded.
|
||||
using ws_type = websocket::stream<beast::ssl_stream<
|
||||
beast::tcp_stream<net::io_context::executor_type>>>;
|
||||
|
||||
// Report a failure
|
||||
void
|
||||
fail(beast::error_code ec, char const* what)
|
||||
@ -49,14 +53,13 @@ fail(beast::error_code ec, char const* what)
|
||||
// Echoes back all received WebSocket messages
|
||||
void
|
||||
do_session(
|
||||
tcp::socket& socket,
|
||||
ssl::context& ctx,
|
||||
ws_type& ws,
|
||||
net::yield_context yield)
|
||||
{
|
||||
beast::error_code ec;
|
||||
|
||||
// Construct the stream by moving in the socket
|
||||
websocket::stream<ssl::stream<tcp::socket&>> ws{socket, ctx};
|
||||
// Set the timeout.
|
||||
beast::get_lowest_layer(ws).expires_after(std::chrono::seconds(30));
|
||||
|
||||
// Perform the SSL handshake
|
||||
ws.next_layer().async_handshake(ssl::stream_base::server, yield[ec]);
|
||||
@ -135,8 +138,7 @@ do_listen(
|
||||
acceptor.get_executor().context(),
|
||||
std::bind(
|
||||
&do_session,
|
||||
std::move(socket),
|
||||
std::ref(ctx),
|
||||
ws_type(std::move(socket), ctx),
|
||||
std::placeholders::_1));
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,6 @@
|
||||
|
||||
#include <boost/beast/core.hpp>
|
||||
#include <boost/beast/websocket.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/asio/spawn.hpp>
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
@ -34,6 +33,11 @@ using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// The type of websocket stream to use
|
||||
// Stackful coroutines are already stranded.
|
||||
using ws_type = websocket::stream<
|
||||
beast::tcp_stream<net::io_context::executor_type>>;
|
||||
|
||||
// Report a failure
|
||||
void
|
||||
fail(beast::error_code ec, char const* what)
|
||||
@ -43,13 +47,10 @@ fail(beast::error_code ec, char const* what)
|
||||
|
||||
// Echoes back all received WebSocket messages
|
||||
void
|
||||
do_session(tcp::socket& socket, net::yield_context yield)
|
||||
do_session(ws_type& ws, net::yield_context yield)
|
||||
{
|
||||
beast::error_code ec;
|
||||
|
||||
// Construct the stream by moving in the socket
|
||||
websocket::stream<tcp::socket> ws{std::move(socket)};
|
||||
|
||||
// Accept the websocket handshake
|
||||
ws.async_accept(yield[ec]);
|
||||
if(ec)
|
||||
@ -121,7 +122,7 @@ do_listen(
|
||||
acceptor.get_executor().context(),
|
||||
std::bind(
|
||||
&do_session,
|
||||
std::move(socket),
|
||||
ws_type(std::move(socket)),
|
||||
std::placeholders::_1));
|
||||
}
|
||||
}
|
||||
|
@ -30,10 +30,8 @@
|
||||
#include <boost/beast/http.hpp>
|
||||
#include <boost/beast/version.hpp>
|
||||
#include <boost/beast/websocket.hpp>
|
||||
#include <boost/asio/bind_executor.hpp>
|
||||
#include <boost/asio/spawn.hpp>
|
||||
#include <boost/asio/strand.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <functional>
|
||||
@ -80,12 +78,16 @@ setup_stream(websocket::stream<NextLayer>& ws)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// The type of websocket stream to use
|
||||
// Stackful coroutines are already stranded.
|
||||
using ws_type = websocket::stream<
|
||||
beast::tcp_stream<net::io_context::executor_type>>;
|
||||
|
||||
void
|
||||
do_sync_session(tcp::socket& socket)
|
||||
do_sync_session(ws_type& ws)
|
||||
{
|
||||
beast::error_code ec;
|
||||
|
||||
websocket::stream<tcp::socket> ws{std::move(socket)};
|
||||
setup_stream(ws);
|
||||
|
||||
ws.accept_ex(
|
||||
@ -131,7 +133,7 @@ do_sync_listen(
|
||||
|
||||
std::thread{std::bind(
|
||||
&do_sync_session,
|
||||
std::move(socket))}.detach();
|
||||
ws_type(std::move(socket)))}.detach();
|
||||
}
|
||||
}
|
||||
|
||||
@ -140,9 +142,7 @@ do_sync_listen(
|
||||
// Echoes back all received WebSocket messages
|
||||
class async_session : public std::enable_shared_from_this<async_session>
|
||||
{
|
||||
websocket::stream<tcp::socket> ws_;
|
||||
net::strand<
|
||||
net::io_context::executor_type> strand_;
|
||||
websocket::stream<beast::tcp_stream<net::io_context::strand>> ws_;
|
||||
beast::multi_buffer buffer_;
|
||||
|
||||
public:
|
||||
@ -150,7 +150,6 @@ public:
|
||||
explicit
|
||||
async_session(tcp::socket socket)
|
||||
: ws_(std::move(socket))
|
||||
, strand_(ws_.get_executor())
|
||||
{
|
||||
setup_stream(ws_);
|
||||
}
|
||||
@ -166,12 +165,10 @@ public:
|
||||
res.set(http::field::server,
|
||||
"Boost.Beast/" + std::to_string(BOOST_BEAST_VERSION) + "-Async");
|
||||
},
|
||||
net::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&async_session::on_accept,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
std::bind(
|
||||
&async_session::on_accept,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1));
|
||||
}
|
||||
|
||||
void
|
||||
@ -190,13 +187,11 @@ public:
|
||||
// Read a message into our buffer
|
||||
ws_.async_read(
|
||||
buffer_,
|
||||
net::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&async_session::on_read,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
std::bind(
|
||||
&async_session::on_read,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
}
|
||||
|
||||
void
|
||||
@ -217,13 +212,11 @@ public:
|
||||
ws_.text(ws_.got_text());
|
||||
ws_.async_write(
|
||||
buffer_.data(),
|
||||
net::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&async_session::on_write,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
std::bind(
|
||||
&async_session::on_write,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
}
|
||||
|
||||
void
|
||||
@ -247,18 +240,13 @@ public:
|
||||
// Accepts incoming connections and launches the sessions
|
||||
class async_listener : public std::enable_shared_from_this<async_listener>
|
||||
{
|
||||
net::strand<
|
||||
net::io_context::executor_type> strand_;
|
||||
tcp::acceptor acceptor_;
|
||||
tcp::socket socket_;
|
||||
|
||||
public:
|
||||
async_listener(
|
||||
net::io_context& ioc,
|
||||
tcp::endpoint endpoint)
|
||||
: strand_(ioc.get_executor())
|
||||
, acceptor_(ioc)
|
||||
, socket_(ioc)
|
||||
: acceptor_(ioc)
|
||||
{
|
||||
beast::error_code ec;
|
||||
|
||||
@ -309,17 +297,15 @@ public:
|
||||
do_accept()
|
||||
{
|
||||
acceptor_.async_accept(
|
||||
socket_,
|
||||
net::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&async_listener::on_accept,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
std::bind(
|
||||
&async_listener::on_accept,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
}
|
||||
|
||||
void
|
||||
on_accept(beast::error_code ec)
|
||||
on_accept(beast::error_code ec, tcp::socket socket)
|
||||
{
|
||||
if(ec)
|
||||
{
|
||||
@ -328,7 +314,7 @@ public:
|
||||
else
|
||||
{
|
||||
// Create the async_session and run it
|
||||
std::make_shared<async_session>(std::move(socket_))->run();
|
||||
std::make_shared<async_session>(std::move(socket))->run();
|
||||
}
|
||||
|
||||
// Accept another connection
|
||||
@ -339,11 +325,10 @@ public:
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void
|
||||
do_coro_session(tcp::socket& socket, net::yield_context yield)
|
||||
do_coro_session(ws_type& ws, net::yield_context yield)
|
||||
{
|
||||
beast::error_code ec;
|
||||
|
||||
websocket::stream<tcp::socket> ws{std::move(socket)};
|
||||
setup_stream(ws);
|
||||
|
||||
ws.async_accept_ex(
|
||||
@ -413,7 +398,7 @@ do_coro_listen(
|
||||
acceptor.get_executor().context(),
|
||||
std::bind(
|
||||
&do_coro_session,
|
||||
std::move(socket),
|
||||
ws_type(std::move(socket)),
|
||||
std::placeholders::_1));
|
||||
}
|
||||
}
|
||||
|
@ -18,10 +18,8 @@
|
||||
#include <boost/beast/core.hpp>
|
||||
#include <boost/beast/websocket.hpp>
|
||||
#include <boost/beast/websocket/ssl.hpp>
|
||||
#include <boost/asio/bind_executor.hpp>
|
||||
#include <boost/beast/_experimental/core/ssl_stream.hpp>
|
||||
#include <boost/asio/coroutine.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/asio/ssl/stream.hpp>
|
||||
#include <boost/asio/strand.hpp>
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
@ -53,18 +51,14 @@ class session
|
||||
: public net::coroutine
|
||||
, public std::enable_shared_from_this<session>
|
||||
{
|
||||
tcp::socket socket_;
|
||||
websocket::stream<ssl::stream<tcp::socket&>> ws_;
|
||||
net::strand<
|
||||
net::io_context::executor_type> strand_;
|
||||
websocket::stream<beast::ssl_stream<
|
||||
beast::tcp_stream<net::io_context::strand>>> ws_;
|
||||
beast::multi_buffer buffer_;
|
||||
|
||||
public:
|
||||
// Take ownership of the socket
|
||||
session(tcp::socket socket, ssl::context& ctx)
|
||||
: socket_(std::move(socket))
|
||||
, ws_(socket_, ctx)
|
||||
, strand_(ws_.get_executor())
|
||||
session(tcp::socket&& socket, ssl::context& ctx)
|
||||
: ws_(std::move(socket), ctx)
|
||||
{
|
||||
}
|
||||
|
||||
@ -88,25 +82,21 @@ public:
|
||||
// Perform the SSL handshake
|
||||
yield ws_.next_layer().async_handshake(
|
||||
ssl::stream_base::server,
|
||||
net::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&session::loop,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
0)));
|
||||
std::bind(
|
||||
&session::loop,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
0));
|
||||
if(ec)
|
||||
return fail(ec, "handshake");
|
||||
|
||||
// Accept the websocket handshake
|
||||
yield ws_.async_accept(
|
||||
net::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&session::loop,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
0)));
|
||||
std::bind(
|
||||
&session::loop,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
0));
|
||||
if(ec)
|
||||
return fail(ec, "accept");
|
||||
|
||||
@ -115,13 +105,11 @@ public:
|
||||
// Read a message into our buffer
|
||||
yield ws_.async_read(
|
||||
buffer_,
|
||||
net::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&session::loop,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
std::bind(
|
||||
&session::loop,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
if(ec == websocket::error::closed)
|
||||
{
|
||||
// This indicates that the session was closed
|
||||
@ -134,13 +122,11 @@ public:
|
||||
ws_.text(ws_.got_text());
|
||||
yield ws_.async_write(
|
||||
buffer_.data(),
|
||||
net::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&session::loop,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
std::bind(
|
||||
&session::loop,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
if(ec)
|
||||
return fail(ec, "write");
|
||||
|
||||
|
@ -15,10 +15,8 @@
|
||||
|
||||
#include <boost/beast/core.hpp>
|
||||
#include <boost/beast/websocket.hpp>
|
||||
#include <boost/asio/bind_executor.hpp>
|
||||
#include <boost/asio/coroutine.hpp>
|
||||
#include <boost/asio/strand.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <functional>
|
||||
@ -48,9 +46,8 @@ class session
|
||||
: public net::coroutine
|
||||
, public std::enable_shared_from_this<session>
|
||||
{
|
||||
websocket::stream<tcp::socket> ws_;
|
||||
net::strand<
|
||||
net::io_context::executor_type> strand_;
|
||||
websocket::stream<
|
||||
beast::tcp_stream<net::io_context::strand>> ws_;
|
||||
beast::multi_buffer buffer_;
|
||||
|
||||
public:
|
||||
@ -58,7 +55,6 @@ public:
|
||||
explicit
|
||||
session(tcp::socket socket)
|
||||
: ws_(std::move(socket))
|
||||
, strand_(ws_.get_executor())
|
||||
{
|
||||
}
|
||||
|
||||
@ -80,13 +76,11 @@ public:
|
||||
{
|
||||
// Accept the websocket handshake
|
||||
yield ws_.async_accept(
|
||||
net::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&session::loop,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
0)));
|
||||
std::bind(
|
||||
&session::loop,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
0));
|
||||
if(ec)
|
||||
return fail(ec, "accept");
|
||||
|
||||
@ -95,13 +89,11 @@ public:
|
||||
// Read a message into our buffer
|
||||
yield ws_.async_read(
|
||||
buffer_,
|
||||
net::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&session::loop,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
std::bind(
|
||||
&session::loop,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
if(ec == websocket::error::closed)
|
||||
{
|
||||
// This indicates that the session was closed
|
||||
@ -114,13 +106,11 @@ public:
|
||||
ws_.text(ws_.got_text());
|
||||
yield ws_.async_write(
|
||||
buffer_.data(),
|
||||
net::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&session::loop,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
std::bind(
|
||||
&session::loop,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
if(ec)
|
||||
return fail(ec, "write");
|
||||
|
||||
|
Reference in New Issue
Block a user