mirror of
https://github.com/boostorg/mqtt5.git
synced 2025-07-30 04:27:34 +02:00
[mqtt-client] added chapter on different ways to establish network connection
Summary: related to T12804 - added chapter on network connection - added code examples - remove any_authenticator from doc targets - manually create table of contents Reviewers: ivica Reviewed By: ivica Subscribers: miljen, iljazovic Differential Revision: https://repo.mireo.local/D26401
This commit is contained in:
@ -34,7 +34,6 @@ make xml/index.xml
|
||||
../include/async_mqtt5/error.hpp
|
||||
../include/async_mqtt5/types.hpp
|
||||
../include/async_mqtt5/mqtt_client.hpp
|
||||
../include/async_mqtt5/detail/any_authenticator.hpp
|
||||
:
|
||||
@call-doxygen
|
||||
;
|
||||
@ -130,9 +129,7 @@ boostbook async_mqtt5
|
||||
<xsl:param>chapter.autolabel=1
|
||||
<xsl:param>chunk.section.depth=8
|
||||
<xsl:param>chunk.first.sections=1
|
||||
<xsl:param>toc.section.depth=2
|
||||
<xsl:param>toc.max.depth=1
|
||||
<xsl:param>generate.toc="chapter toc,title section nop reference nop part toc"
|
||||
<xsl:param>generate.toc=""
|
||||
<xsl:param>html.stylesheet=boostbook.css
|
||||
:
|
||||
<dependency>stylesheets
|
||||
|
@ -29,6 +29,8 @@
|
||||
[template beastconceptslink[id term][@boost:/libs/beast/doc/html/beast/concepts/[id].html [term]]]
|
||||
[template mqttlink[id text][@https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc[id] [text]]]
|
||||
|
||||
[def __OPENSSL__ [@https://www.openssl.org/ OpenSSL]]
|
||||
|
||||
[def __CompletionToken__ [@boost:/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.completion_tokens_and_handlers CompletionToken]]
|
||||
[def __ExecutionContext__ [reflink ExecutionContext]]
|
||||
[def __StreamType__ [reflink StreamType]]
|
||||
@ -37,11 +39,17 @@
|
||||
|
||||
[def __Boost__ [@https://www.boost.org/ Boost]]
|
||||
[def __Asio__ [@boost:/libs/asio/index.html Boost.Asio]]
|
||||
[def __Beast__ [@boost:/libs/beast/index.html Boost.Beast]]
|
||||
[def __ASIO_PER_OP_CANCELLATION__ [@boost:/doc/html/boost_asio/overview/core/cancellation.html Per-Operation Cancellation]]
|
||||
[def __POST__ [@boost:doc/html/boost_asio/reference/post.html `boost::asio::post`]]
|
||||
[def __CO_SPAWN__ [@boost:/doc/html/boost_asio/reference/co_spawn.html `boost::asio::co_spawn`]]
|
||||
[def __USE_AWAITABLE__ [@boost:/doc/html/boost_asio/reference/use_awaitable.html `boost::asio::use_awaitable`]]
|
||||
[def __USE_FUTURE__ [@boost:/doc/html/boost_asio/reference/use_future.html `boost::asio::use_future`]]
|
||||
[def __SSL__ [@boost:/doc/html/boost_asio/overview/ssl.html `SSL`]]
|
||||
[def __TCP_SOCKET__ [asioreflink ip__tcp/socket ip::tcp::socket]]
|
||||
[def __SSL_CONTEXT__ [asioreflink ssl__context ssl::context]]
|
||||
[def __SSL_STREAM__ [asioreflink ssl__stream ssl::stream<__TCP_SOCKET__>]]
|
||||
[def __WEBSOCKET_STREAM__ [beastreflink boost__beast__websocket__stream websocket::stream<NextLayer>]]
|
||||
|
||||
[def __Self__ [reflink2 mqtt_client `mqtt_client`]]
|
||||
|
||||
@ -95,11 +103,24 @@
|
||||
[def __REASON_CODES__ [reflink2 Reason_codes `Reason Codes`]]
|
||||
[def __ERROR_HANDLING__ [reflink2 Error_handling `Error handling`]]
|
||||
|
||||
[def __EXAMPLE_CALLBACK__ [link async_mqtt5.async_examples.callbacks Async functions with callbacks]]
|
||||
[def __EXAMPLE_COROUTINE__ [link async_mqtt5.async_examples.cpp20_coroutines Async functions with C++20 coroutines]]
|
||||
[def __EXAMPLE_FUTURE__ [link async_mqtt5.async_examples.futures Async functions with futures]]
|
||||
[def __EXAMPLE_CALLBACK__ [link async_mqtt5.examples.asio.callbacks Async functions with callbacks]]
|
||||
[def __EXAMPLE_COROUTINE__ [link async_mqtt5.examples.asio.cpp20_coroutines Async functions with C++20 coroutines]]
|
||||
[def __EXAMPLE_FUTURE__ [link async_mqtt5.examples.asio.futures Async functions with futures]]
|
||||
|
||||
[include 01_intro.qbk]
|
||||
[include 02_examples.qbk]
|
||||
|
||||
[include reference/reference.qbk]
|
||||
|
||||
[h3 Table of Contents]
|
||||
* [link async_mqtt5.intro Introduction]
|
||||
* [link async_mqtt5.examples Examples]
|
||||
* [link async_mqtt5.examples.network_connection Establishing a network connection with different protocols]
|
||||
* [link async_mqtt5.examples.network_connection.tcp_ip_connection TCP/IP connection]
|
||||
* [link async_mqtt5.examples.network_connection.tls_ssl_connection TLS/SSL connection]
|
||||
* [link async_mqtt5.examples.network_connection.websocket_connection WebSocket connection]
|
||||
* [link async_mqtt5.examples.asio Compatibility with Boost.Asio]
|
||||
* [link async_mqtt5.examples.asio.callbacks Async functions with callbacks]
|
||||
* [link async_mqtt5.examples.asio.cpp20_coroutines Async functions with C++20 coroutines]
|
||||
* [link async_mqtt5.examples.asio.futures Async functions with futures]
|
||||
* [link async_mqtt5.ref Reference]
|
||||
|
@ -5,36 +5,23 @@
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
]
|
||||
|
||||
[section:async_examples Compatibility with Boost.Asio]
|
||||
The __Self__ is built upon __Asio__ and thus follows the same principles.
|
||||
This section illustrates the usage of __Self__ async
|
||||
functions with different __CompletionToken__.
|
||||
[section:examples Examples]
|
||||
The following examples demonstrate how to use __Self__ in different scenarios.
|
||||
|
||||
# [link async_mqtt5.async_examples.callbacks Async functions with callbacks]
|
||||
# [link async_mqtt5.async_examples.cpp20_coroutines Async functions with C++20 coroutines]
|
||||
# [link async_mqtt5.async_examples.futures Async functions with futures]
|
||||
The first section will show how to use different underlying transport protocols (such as TCP, SSL and WebSocket)
|
||||
to establish a connection to a MQTT Broker.
|
||||
|
||||
* [link async_mqtt5.examples.network_connection Establishing a network connection with different protocols]
|
||||
|
||||
[section:callbacks Async functions with callbacks]
|
||||
This example demonstrates how to use __Self__ asynchrous functions with callbacks.
|
||||
The second section will showcase how to use asynchronous functions in __Self__
|
||||
with different __CompletionToken__.
|
||||
|
||||
[import ../../example/callbacks.cpp]
|
||||
[callbacks_examples]
|
||||
[endsect]
|
||||
* [link async_mqtt5.examples.asio Compatibility with Boost.Asio]
|
||||
* [link async_mqtt5.examples.asio.callbacks Async functions with callbacks]
|
||||
* [link async_mqtt5.examples.asio.cpp20_coroutines Async functions with C++20 coroutines]
|
||||
* [link async_mqtt5.examples.asio.futures Async functions with futures]
|
||||
|
||||
[section:cpp20_coroutines Async functions with C++20 coroutines]
|
||||
This example demonstrates how to use __Self__ asynchrous functions with C++20 coroutines
|
||||
using __USE_AWAITABLE__ and __CO_SPAWN__.
|
||||
|
||||
[import ../../example/cpp20_coroutines.cpp]
|
||||
[cpp20_coroutines_examples]
|
||||
[endsect]
|
||||
|
||||
[section:futures Async functions with futures]
|
||||
This example demonstrates how to use __Self__ asynchrous functions with __USE_FUTURE__
|
||||
completion token.
|
||||
[import ../../example/futures.cpp]
|
||||
[futures_examples]
|
||||
[endsect]
|
||||
[include examples/Network_connection.qbk]
|
||||
[include examples/Asio_compatibility.qbk]
|
||||
|
||||
[endsect]
|
||||
|
40
doc/qbk/examples/Asio_compatibility.qbk
Normal file
40
doc/qbk/examples/Asio_compatibility.qbk
Normal file
@ -0,0 +1,40 @@
|
||||
[/
|
||||
Copyright (c) 2023 Mireo
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
]
|
||||
|
||||
[section:asio Compatibility with Boost.Asio]
|
||||
The __Self__ is built upon __Asio__ and thus follows the same principles.
|
||||
This section illustrates the usage of __Self__ async
|
||||
functions with different __CompletionToken__.
|
||||
|
||||
# [link async_mqtt5.examples.asio.callbacks Async functions with callbacks]
|
||||
# [link async_mqtt5.examples.asio.cpp20_coroutines Async functions with C++20 coroutines]
|
||||
# [link async_mqtt5.examples.asio.futures Async functions with futures]
|
||||
|
||||
|
||||
[section:callbacks Async functions with callbacks]
|
||||
This example demonstrates how to use __Self__ asynchrous functions with callbacks.
|
||||
|
||||
[import ../../../example/callbacks.cpp]
|
||||
[callbacks_examples]
|
||||
[endsect]
|
||||
|
||||
[section:cpp20_coroutines Async functions with C++20 coroutines]
|
||||
This example demonstrates how to use __Self__ asynchrous functions with C++20 coroutines
|
||||
using __USE_AWAITABLE__ and __CO_SPAWN__.
|
||||
|
||||
[import ../../../example/cpp20_coroutines.cpp]
|
||||
[cpp20_coroutines_examples]
|
||||
[endsect]
|
||||
|
||||
[section:futures Async functions with futures]
|
||||
This example demonstrates how to use __Self__ asynchrous functions with __USE_FUTURE__
|
||||
completion token.
|
||||
[import ../../../example/futures.cpp]
|
||||
[futures_examples]
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
43
doc/qbk/examples/Network_connection.qbk
Normal file
43
doc/qbk/examples/Network_connection.qbk
Normal file
@ -0,0 +1,43 @@
|
||||
[/
|
||||
Copyright (c) 2023 Mireo
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
]
|
||||
|
||||
[section:network_connection Establishing a network connection with different protocols ]
|
||||
The __MQTT__ protocol requires the underlying transport protocol that ensures
|
||||
orderly, lossless transmission of byte streams between the Client and Server in both directions.
|
||||
|
||||
The following examples demonstrate how to establish a network connection using suitable
|
||||
transport protocols such as TCP/IP, TLS/SSL, and WebSocket.
|
||||
|
||||
[import ../../../example/network_connection.cpp]
|
||||
|
||||
[h3 TCP/IP connection]
|
||||
To create a TCP/IP connection with a Broker, initialize __Self__ with __TCP_SOCKET__ as the __StreamType__.
|
||||
[tcp]
|
||||
|
||||
[h3 TLS/SSL connection]
|
||||
To establish a secure and encrypted connection using the TLS/SSL protocol, supply a context object that meets the __TlsContext__ requirements.
|
||||
Additionally, initialize __Self__ with an underlying stream that implements TLS/SSL protocol as the __StreamType__.
|
||||
|
||||
This example will demonstrate how to set up an SSL connection using __SSL_CONTEXT__ and __SSL_STREAM__.
|
||||
To use SSL support in __Asio__, __OPENSSL__ is required.
|
||||
[tls]
|
||||
|
||||
[h3 WebSocket connection]
|
||||
The WebSocket connection can be established over an unencrypted TCP/IP connection or an encrypted TLS/SSL connection.
|
||||
|
||||
The following example will showcase setting up WebSocket over TCP/IP and WebSocket over TLS/SLL connection using
|
||||
__WEBSOCKET_STREAM__.
|
||||
|
||||
[h4 WebSocket over TCP/IP]
|
||||
[websocket_tcp]
|
||||
|
||||
[h4 WebSocket over TLS/SSL]
|
||||
[websocket_tls]
|
||||
|
||||
Once the __Self__ has been initialized with a suitable __StreamType__, it is prepared for configuration and utilization.
|
||||
|
||||
[endsect]
|
@ -13,11 +13,8 @@
|
||||
|
||||
Additionally, it should follow Asio's layered stream model by having a `lowest_layer_type` member type,
|
||||
and a `lowest_layer` member function, returing a `lowest_layer_type&`.
|
||||
The `lowest_layer_type` should inherit from [asioreflink basic_stream_socket basic_stream_socket].
|
||||
The `lowest_layer_type` should inherit from __TCP_SOCKET__.
|
||||
|
||||
The types [asioreflink basic_stream_socket basic_stream_socket<Protocol, Executor>],
|
||||
[asioreflink ssl__stream ssl::stream<Stream>], and
|
||||
[beastreflink boost__beast__websocket__stream websocket::stream<NextLayer>]
|
||||
meet these requirements.
|
||||
The types __TCP_SOCKET__, __SSL_STREAM__ and __WEBSOCKET_STREAM__ meet these requirements.
|
||||
|
||||
[endsect]
|
||||
|
@ -72,7 +72,6 @@ WARN_LOGFILE =
|
||||
INPUT = ../include/async_mqtt5/error.hpp \
|
||||
../include/async_mqtt5/types.hpp \
|
||||
../include/async_mqtt5/mqtt_client.hpp \
|
||||
../include/async_mqtt5/detail/any_authenticator.hpp
|
||||
FILE_PATTERNS =
|
||||
RECURSIVE = NO
|
||||
EXCLUDE =
|
||||
|
@ -20,7 +20,7 @@ using client_type = async_mqtt5::mqtt_client<stream_type>;
|
||||
* When an asynchronous function is called, the coroutine is suspended.
|
||||
* After the asynchronous operation finishes, the coroutine resumes from the point it was suspended.
|
||||
*
|
||||
* In this example, each asynchronous function is invoked with boost::asio::use_awaitable completion token.
|
||||
* In this example, each asynchronous function is invoked with ``__USE_AWAITABLE__`` completion token.
|
||||
* When using this completion token, co_await will throw exceptions instead of returning an error code.
|
||||
* If you do not wish to throw exceptions, refer to the following use_nothrow_awaitable and nothrow_coroutine() example.
|
||||
*/
|
||||
@ -100,7 +100,7 @@ asio::awaitable<void> coroutine(client_type& client) {
|
||||
}
|
||||
|
||||
/**
|
||||
* A modified completion token. Using this completion token instead of asio::use_awaitable
|
||||
* A modified completion token. Using this completion token instead of ``__USE_AWAITABLE__``
|
||||
* will prevent co_await from throwing exceptions. Instead, co_await will return the error code
|
||||
* along with other values specified in the handler signature.
|
||||
*/
|
||||
|
@ -70,7 +70,7 @@ void run_with_future(client_type& client) {
|
||||
std::cout << "Subscribe Reason Code: " << sub_rcs[0].message() << std::endl;
|
||||
|
||||
// Note: the get() call on async_receive future could block indefinitely if the mqtt_client
|
||||
// failed to subscribe or there are no Application Messages to be received from the subcribed Topic!
|
||||
// failed to subscribe or there are no Application Messages to be received from the subscribed Topic!
|
||||
if (!sub_rcs[0]) {
|
||||
using rec_fut_type = std::tuple<std::string, std::string, async_mqtt5::publish_props>;
|
||||
std::future<rec_fut_type> rec_fut = client.async_receive(asio::use_future);
|
||||
|
164
example/network_connection.cpp
Normal file
164
example/network_connection.cpp
Normal file
@ -0,0 +1,164 @@
|
||||
//[network_connectiong
|
||||
|
||||
|
||||
//[tcp
|
||||
#include <boost/asio/io_context.hpp>
|
||||
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
|
||||
#include <async_mqtt5.hpp>
|
||||
|
||||
void tcp_setup() {
|
||||
boost::asio::io_context ioc;
|
||||
|
||||
// Use ``__TCP_SOCKET__`` as the underlying stream.
|
||||
async_mqtt5::mqtt_client<boost::asio::ip::tcp::socket> client(ioc, "");
|
||||
}
|
||||
|
||||
//]
|
||||
|
||||
|
||||
//[tls
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/asio/ssl.hpp>
|
||||
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
|
||||
#include <async_mqtt5.hpp>
|
||||
|
||||
|
||||
// External customization point.
|
||||
namespace async_mqtt5 {
|
||||
|
||||
// This client uses this funcction to indicate which hostname it is
|
||||
// attempting to connect to at the start of the handshaking process.
|
||||
template <typename StreamBase>
|
||||
void assign_tls_sni(
|
||||
const authority_path& ap,
|
||||
boost::asio::ssl::context& ctx,
|
||||
boost::asio::ssl::stream<StreamBase>& stream
|
||||
) {
|
||||
SSL_set_tlsext_host_name(stream.native_handle(), ap.host.c_str());
|
||||
}
|
||||
|
||||
} // end namespace async_mqtt5
|
||||
|
||||
// The certificate file in PEM format.
|
||||
constexpr char certificate[] =
|
||||
"-----BEGIN CERTIFICATE-----\n"
|
||||
"...........................\n"
|
||||
"-----END CERTIFICATE-----\n"
|
||||
;
|
||||
|
||||
void ssl_setup() {
|
||||
boost::asio::io_context ioc;
|
||||
|
||||
// Context satisfying ``__TlsContext__`` requirements that the underlying SSL stream will use.
|
||||
// The purpose of the context is to allow us to set up TLS/SSL-related options.
|
||||
// See ``__SSL__`` for more information and options.
|
||||
boost::asio::ssl::context context(boost::asio::ssl::context::tls_client);
|
||||
|
||||
async_mqtt5::error_code ec;
|
||||
|
||||
// Add the trusted certificate authority for performing verification.
|
||||
context.add_certificate_authority(boost::asio::buffer(certificate), ec);
|
||||
|
||||
// Set peer verification mode used by the context.
|
||||
// This will verify that the server's certificate is valid and signed by a trusted certificate authority.
|
||||
context.set_verify_mode(boost::asio::ssl::verify_peer, ec);
|
||||
|
||||
// Use ``__SSL_STREAM__`` as the ``__StreamType__`` with ``__SSL_CONTEXT__`` as the ``__TlsContext__``.
|
||||
async_mqtt5::mqtt_client<
|
||||
boost::asio::ssl::stream<boost::asio::ip::tcp::socket>,
|
||||
boost::asio::ssl::context
|
||||
> client(ioc, "", std::move(context));
|
||||
}
|
||||
//]
|
||||
|
||||
//[websocket_tcp
|
||||
#include <boost/asio/io_context.hpp>
|
||||
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
|
||||
#include <boost/beast/websocket.hpp>
|
||||
|
||||
#include <async_mqtt5.hpp>
|
||||
|
||||
void websocket_tcp_setup() {
|
||||
boost::asio::io_context ioc;
|
||||
|
||||
// Use ``[beastreflink boost__beast__websocket__stream websocket::stream<__TCP_SOCKET__>]`` as the underlying stream.
|
||||
async_mqtt5::mqtt_client<
|
||||
boost::beast::websocket::stream<boost::asio::ip::tcp::socket>
|
||||
> client(ioc, "");
|
||||
}
|
||||
|
||||
//]
|
||||
|
||||
//[websocket_tls
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/asio/ssl.hpp>
|
||||
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
|
||||
#include <boost/beast/websocket.hpp>
|
||||
|
||||
#include <async_mqtt5.hpp>
|
||||
|
||||
constexpr char ca[] =
|
||||
"-----BEGIN CERTIFICATE-----\n"
|
||||
"...........................\n"
|
||||
"-----END CERTIFICATE-----\n"
|
||||
;
|
||||
|
||||
namespace boost::beast::websocket {
|
||||
|
||||
// ``[beastreflink boost__beast__websocket__async_teardown boost::beast::websocket::async_teardown]`` is a free function
|
||||
// designed to initiate the asynchronous teardown of a connection.
|
||||
// The specific behaviour of this function is based on the NextLayer type (Socket type) used to create the ``__WEBSOCKET_STREAM__``.
|
||||
// ``__Beast__`` library includes an implementation of this function for ``__TCP_SOCKET__``.
|
||||
// However, the callers are responsible for providing a suitable overload of this function for any other type,
|
||||
// such as ``__SSL_STREAM__`` as shown in this example.
|
||||
template <typename TeardownHandler>
|
||||
void async_teardown(
|
||||
boost::beast::role_type role,
|
||||
asio::ssl::stream<asio::ip::tcp::socket>& stream,
|
||||
TeardownHandler&& handler
|
||||
) {
|
||||
return stream.async_shutdown(std::forward<TeardownHandler>(handler));
|
||||
}
|
||||
|
||||
} // end namespace boost::beast::websocket
|
||||
|
||||
namespace async_mqtt5 {
|
||||
|
||||
template <typename streambase>
|
||||
void assign_tls_sni(
|
||||
const authority_path& ap,
|
||||
asio::ssl::context& ctx,
|
||||
asio::ssl::stream<streambase>& stream
|
||||
) {
|
||||
ssl_set_tlsext_host_name(stream.native_handle(), ap.host.c_str());
|
||||
}
|
||||
|
||||
} // end namespace async_mqtt5
|
||||
|
||||
void websocket_tls_setup() {
|
||||
boost::asio::io_context ioc;
|
||||
|
||||
boost::asio::ssl::context context(boost::asio::ssl::context::tls_client);
|
||||
|
||||
async_mqtt5::error_code ec;
|
||||
context.add_certificate_authority(boost::asio::buffer(ca), ec);
|
||||
context.set_verify_mode(boost::asio::ssl::verify_peer, ec);
|
||||
|
||||
async_mqtt5::mqtt_client<
|
||||
boost::beast::websocket::stream<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>>,
|
||||
boost::asio::ssl::context
|
||||
> client(ioc, "", std::move(context));
|
||||
}
|
||||
|
||||
//]
|
||||
|
||||
|
||||
//]
|
@ -85,13 +85,18 @@ public:
|
||||
mqtt_client(context.get_executor(), cnf, std::move(tls_context))
|
||||
{}
|
||||
|
||||
/// Move-construct an mqtt_client from another.
|
||||
/** Moved-from client can only be destructed. */
|
||||
/**
|
||||
* \brief Move-construct an mqtt_client from another.
|
||||
*
|
||||
* \details Moved-from client can only be destructed
|
||||
*/
|
||||
mqtt_client(mqtt_client&& other) noexcept = default;
|
||||
|
||||
/// Move-assign an mqtt_client from another.
|
||||
/** Cancels this client first.
|
||||
* Moved-from client can only be destructed.
|
||||
|
||||
/**
|
||||
* \brief Move assignment operator.
|
||||
*
|
||||
* \details Cancels this client first. Moved-from client can only be destructed.
|
||||
*/
|
||||
mqtt_client& operator=(mqtt_client&& other) noexcept {
|
||||
cancel();
|
||||
|
Reference in New Issue
Block a user