1
0
mirror of https://github.com/FreeRTOS/coreMQTT synced 2025-05-12 21:35:41 +08:00
coreMQTT/latest/mqtt_design.html

197 lines
16 KiB
HTML

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=11"/>
<meta name="generator" content="Doxygen 1.9.6"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>coreMQTT: Design</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="dynsections.js"></script>
<link href="navtree.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="resize.js"></script>
<script type="text/javascript" src="navtreedata.js"></script>
<script type="text/javascript" src="navtree.js"></script>
<link href="search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="search/searchdata.js"></script>
<script type="text/javascript" src="search/search.js"></script>
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&amp;dn=expat.txt MIT */
$(document).ready(function() { init_search(); });
/* @license-end */
</script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
<link href="style.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr id="projectrow">
<td id="projectalign">
<div id="projectname">coreMQTT<span id="projectnumber">&#160;v2.3.1</span>
</div>
<div id="projectbrief">MQTT 3.1.1 Client Library</div>
</td>
<td> <div id="MSearchBox" class="MSearchBoxInactive">
<span class="left">
<span id="MSearchSelect" onmouseover="return searchBox.OnSearchSelectShow()" onmouseout="return searchBox.OnSearchSelectHide()">&#160;</span>
<input type="text" id="MSearchField" value="" placeholder="Search" accesskey="S"
onfocus="searchBox.OnSearchFieldFocus(true)"
onblur="searchBox.OnSearchFieldFocus(false)"
onkeyup="searchBox.OnSearchFieldChange(event)"/>
</span><span class="right">
<a id="MSearchClose" href="javascript:searchBox.CloseResultsWindow()"><img id="MSearchCloseImg" border="0" src="search/close.svg" alt=""/></a>
</span>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.9.6 -->
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&amp;dn=expat.txt MIT */
var searchBox = new SearchBox("searchBox", "search/",'.html');
/* @license-end */
</script>
</div><!-- top -->
<div id="side-nav" class="ui-resizable side-nav-resizable">
<div id="nav-tree">
<div id="nav-tree-contents">
<div id="nav-sync" class="sync"></div>
</div>
</div>
<div id="splitbar" style="-moz-user-select:none;"
class="ui-resizable-handle">
</div>
</div>
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&amp;dn=expat.txt MIT */
$(document).ready(function(){initNavTree('mqtt_design.html',''); initResizable(); });
/* @license-end */
</script>
<div id="doc-content">
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
onmouseover="return searchBox.OnSearchSelectShow()"
onmouseout="return searchBox.OnSearchSelectHide()"
onkeydown="return searchBox.OnSearchSelectKey(event)">
</div>
<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<div id="MSearchResults">
<div class="SRPage">
<div id="SRIndex">
<div id="SRResults"></div>
<div class="SRStatus" id="Loading">Loading...</div>
<div class="SRStatus" id="Searching">Searching...</div>
<div class="SRStatus" id="NoMatches">No Matches</div>
</div>
</div>
</div>
</div>
<div><div class="header">
<div class="headertitle"><div class="title">Design </div></div>
</div><!--header-->
<div class="contents">
<div class="textblock"><p>Architecture of the MQTT library.</p>
<p>This MQTT client library provides an implementation of the <a href="https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html">MQTT 3.1.1 specification</a>. It is optimized for resource constrained devices and does not allocate any memory.</p>
<h1><a class="anchor" id="mqtt_interfaces"></a>
Interfaces and Callbacks</h1>
<p>The MQTT library relies on interfaces to dissociate itself from platform specific functionality, such as the transport layer or maintaining time. Interfaces used by MQTT are simply function pointers with expectations of behavior.</p>
<p>The MQTT library expects the application to provide implementations for the following interfaces:</p>
<table class="doxtable">
<tr>
<td><b>Function Pointer</b> </td><td><b>Use</b> </td></tr>
<tr>
<td><a class="el" href="group__mqtt__callback__types.html#ga227df31d6daf07e5d833537c12130167">TransportRecv_t</a> </td><td>Receiving data from an established network connection. </td></tr>
<tr>
<td><a class="el" href="group__mqtt__callback__types.html#ga2a39853ff952edd715ab07b33ab2a7c5">TransportSend_t</a> </td><td>Sending data over an established network connection. </td></tr>
<tr>
<td><a class="el" href="group__mqtt__callback__types.html#gae3bea55b0e49e5208b8c5709a5ea23aa">MQTTGetCurrentTimeFunc_t</a> </td><td>Obtaining timestamps for complying with user-specified timeouts and the MQTT keep-alive mechanism. </td></tr>
<tr>
<td><a class="el" href="group__mqtt__callback__types.html#ga00d348277ed4fde23c95bfc749ae954a">MQTTEventCallback_t</a> </td><td>Returning packets received from the network to the user application after deserialization. </td></tr>
</table>
<h1><a class="anchor" id="mqtt_serializers"></a>
Serializers and Deserializers</h1>
<p>The managed MQTT API in <a class="el" href="core__mqtt_8h.html">core_mqtt.h</a> uses a set of serialization and deserialization functions declared in <a class="el" href="core__mqtt__serializer_8h.html">core_mqtt_serializer.h</a>. If a user does not want to use the functionality provided by the managed API, these low-level functions can be used directly:</p>
<ul>
<li><a class="el" href="mqtt_getconnectpacketsize_function.html">MQTT_GetConnectPacketSize</a> <br />
</li>
<li><a class="el" href="mqtt_serializeconnect_function.html">MQTT_SerializeConnect</a> <br />
</li>
<li><a class="el" href="mqtt_getsubscribepacketsize_function.html">MQTT_GetSubscribePacketSize</a> <br />
</li>
<li><a class="el" href="mqtt_serializesubscribe_function.html">MQTT_SerializeSubscribe</a> <br />
</li>
<li><a class="el" href="mqtt_getunsubscribepacketsize_function.html">MQTT_GetUnsubscribePacketSize</a> <br />
</li>
<li><a class="el" href="mqtt_serializeunsubscribe_function.html">MQTT_SerializeUnsubscribe</a> <br />
</li>
<li><a class="el" href="mqtt_getpublishpacketsize_function.html">MQTT_GetPublishPacketSize</a> <br />
</li>
<li><a class="el" href="mqtt_serializepublish_function.html">MQTT_SerializePublish</a> <br />
</li>
<li><a class="el" href="mqtt_serializepublishheader_function.html">MQTT_SerializePublishHeader</a> <br />
</li>
<li><a class="el" href="mqtt_serializeack_function.html">MQTT_SerializeAck</a> <br />
</li>
<li><a class="el" href="mqtt_getdisconnectpacketsize_function.html">MQTT_GetDisconnectPacketSize</a> <br />
</li>
<li><a class="el" href="mqtt_serializedisconnect_function.html">MQTT_SerializeDisconnect</a> <br />
</li>
<li><a class="el" href="mqtt_getpingreqpacketsize_function.html">MQTT_GetPingreqPacketSize</a> <br />
</li>
<li><a class="el" href="mqtt_serializepingreq_function.html">MQTT_SerializePingreq</a> <br />
</li>
<li><a class="el" href="mqtt_deserializepublish_function.html">MQTT_DeserializePublish</a> <br />
</li>
<li><a class="el" href="mqtt_deserializeack_function.html">MQTT_DeserializeAck</a> <br />
</li>
<li><a class="el" href="mqtt_getincomingpackettypeandlength_function.html">MQTT_GetIncomingPacketTypeAndLength</a> <br />
</li>
</ul>
<h1><a class="anchor" id="mqtt_sessions"></a>
Sessions and State</h1>
<p>The MQTT 3.1.1 protocol allows for a client and server to maintain persistent sessions, which can be resumed after a reconnect. The elements of a session stored by this client library consist of the states of incomplete publishes with Quality of Service levels of 1 (at least once), or 2 (exactly once). These states are stored in the pointers pointed to by <a class="el" href="struct_m_q_t_t_context__t.html#a4ea1e37e0e81f010fbf84365ac2ef6de">MQTTContext_t::outgoingPublishRecords</a> and <a class="el" href="struct_m_q_t_t_context__t.html#afc147663a5933de81212fa77057f0a4d">MQTTContext_t::incomingPublishRecords</a>; This library does not store any subscription information, nor any information for QoS 0 publishes.</p>
<p>When resuming a persistent session, the client library will resend PUBRELs for all PUBRECs that had been received for incomplete outgoing QoS 2 publishes. If the broker does not resume the session, then all state information in the client will be reset.</p>
<dl class="section note"><dt>Note</dt><dd>The library stores only the <em>state</em> of incomplete publishes and not the publish payloads. It is the responsibility of the user application to save publish payloads until the publish is complete. If a persistent session is resumed, then <a class="el" href="mqtt_publishtoresend_function.html">MQTT_PublishToResend</a> should be called to obtain the packet identifiers of incomplete publishes, followed by a call to <a class="el" href="mqtt_publish_function.html">MQTT_Publish</a> to resend the unacknowledged publish.</dd></dl>
<h1><a class="anchor" id="mqtt_receivepackets"></a>
Packet Reception</h1>
<p>MQTT Packets are received from the network with calls to <a class="el" href="mqtt_processloop_function.html">MQTT_ProcessLoop</a> or <a class="el" href="mqtt_receiveloop_function.html">MQTT_ReceiveLoop</a>. These functions are mostly identical, with the exception of keep-alive; the former sends ping requests and processes ping responses to ensure the MQTT session does not remain idle for more than the keep-alive interval, while the latter does not. Since calls to <a class="el" href="mqtt_publish_function.html">MQTT_Publish</a>, <a class="el" href="mqtt_subscribe_function.html">MQTT_Subscribe</a>, and <a class="el" href="mqtt_unsubscribe_function.html">MQTT_Unsubscribe</a> only send packets and do not wait for acknowledgments, a call to <a class="el" href="mqtt_processloop_function.html">MQTT_ProcessLoop</a> or <a class="el" href="mqtt_receiveloop_function.html">MQTT_ReceiveLoop</a> must follow in order to receive any expected acknowledgment. The exception is <a class="el" href="mqtt_connect_function.html">MQTT_Connect</a>; since a MQTT session cannot be considered established until the server acknowledges a CONNECT packet with a CONNACK, the function waits until the CONNACK is received.</p>
<h2><a class="anchor" id="mqtt_receivetimeout"></a>
Runtime Timeouts passed to MQTT library</h2>
<p><a class="el" href="mqtt_connect_function.html">MQTT_Connect</a>, <a class="el" href="mqtt_processloop_function.html">MQTT_ProcessLoop</a>, and <a class="el" href="mqtt_receiveloop_function.html">MQTT_ReceiveLoop</a> all accept a timeout parameter for packet reception.<br />
For the <a class="el" href="mqtt_connect_function.html">MQTT_Connect</a>, if this value is set to 0, then instead of a time-based loop, it will attempt to call the transport receive function up to a maximum number of retries, which is defined by <a class="el" href="core_mqtt_config.html#MQTT_MAX_CONNACK_RECEIVE_RETRY_COUNT">MQTT_MAX_CONNACK_RECEIVE_RETRY_COUNT</a>.</p>
<p>For <a class="el" href="mqtt_processloop_function.html">MQTT_ProcessLoop</a> and <a class="el" href="mqtt_receiveloop_function.html">MQTT_ReceiveLoop</a>, the timeout value represents the <em>minimum</em> duration that will be spent in the function, provided there are no network errors. Should the timeout be set to 0, then the loop will run for a single iteration. A single iteration of a loop consists of an attempt to receive a single byte from the network, and if the single byte receive was successful, then attempt(s) to receive the rest of the packet (with retry attempts governed by <a class="el" href="core_mqtt_config.html#MQTT_RECV_POLLING_TIMEOUT_MS">MQTT_RECV_POLLING_TIMEOUT_MS</a>), followed by sending acknowledgement response, if needed (with retry attempts governed by <a class="el" href="core_mqtt_config.html#MQTT_SEND_TIMEOUT_MS">MQTT_SEND_TIMEOUT_MS</a>), and then, finally deserialization of the packet received and a call to the application callback. If the first read did not succeed, then instead the library checks if a ping request needs to be sent (only for the process loop).</p>
<p>See the below diagrams for a representation of the above flows: </p><table class="markdownTable">
<tr class="markdownTableHead">
<th class="markdownTableHeadCenter">MQTT Connect Diagram </th><th class="markdownTableHeadCenter">MQTT ProcessLoop Diagram </th><th class="markdownTableHeadCenter">MQTT ReceiveLoop Diagram </th></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyCenter"><img src="mqtt_connect_design.png" alt="MQTT Connect" width="100%" class="inline"/> </td><td class="markdownTableBodyCenter"><img src="mqtt_processloop_design.png" alt="MQTT Process Loop" width="100%" class="inline"/> </td><td class="markdownTableBodyCenter"><img src="mqtt_receiveloop_design.png" alt="MQTT Receive Loop" width="100%" class="inline"/> </td></tr>
</table>
<h1><a class="anchor" id="mqtt_keepalive"></a>
Keep-Alive</h1>
<p>The MQTT standard specifies a keep-alive mechanism to detect half-open or otherwise unusable network connections. An MQTT client will send periodic ping requests (PINGREQ) to the server if the connection is idle. The MQTT server must respond to ping requests with a ping response (PINGRESP).</p>
<p>In this library, <a class="el" href="mqtt_processloop_function.html">MQTT_ProcessLoop</a> handles sending of PINGREQs and processing corresponding PINGRESPs to comply with the keep-alive interval set in <a class="el" href="struct_m_q_t_t_context__t.html#afd6071827ef48b230212a5725c2075be">MQTTContext_t::keepAliveIntervalSec</a>.</p>
<p>The standard does not specify the time duration within which the server has to respond to a ping request, noting only a "reasonable amount of time". If the response to a ping request is not received within <a class="el" href="core_mqtt_config.html#MQTT_PINGRESP_TIMEOUT_MS">MQTT_PINGRESP_TIMEOUT_MS</a>, this library assumes that the connection is dead.</p>
<p>If <a class="el" href="mqtt_receiveloop_function.html">MQTT_ReceiveLoop</a> is used instead of <a class="el" href="mqtt_processloop_function.html">MQTT_ProcessLoop</a>, then no ping requests are sent. The application must ensure the connection does not remain idle for more than the keep-alive interval by calling <a class="el" href="mqtt_ping_function.html">MQTT_Ping</a> to send ping requests. The timestamp in <a class="el" href="struct_m_q_t_t_context__t.html#a01acf90953e830ba3e7f44182cb1d482">MQTTContext_t::lastPacketTxTime</a> indicates when a packet was last sent by the library.</p>
<p>Sending any ping request sets the <a class="el" href="struct_m_q_t_t_context__t.html#ac7073f43645f7b7c0c5b7763980004bb">MQTTContext_t::waitingForPingResp</a> flag. This flag is cleared by <a class="el" href="mqtt_processloop_function.html">MQTT_ProcessLoop</a> when a ping response is received. If <a class="el" href="mqtt_receiveloop_function.html">MQTT_ReceiveLoop</a> is used instead, then this flag must be cleared manually by the application's callback. </p>
</div></div><!-- contents -->
</div><!-- PageDoc -->
</div><!-- doc-content -->
<!-- start footer part -->
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
<ul>
<li class="footer">Generated by <a href="https://www.doxygen.org/index.html"><img class="footer" src="doxygen.svg" width="104" height="31" alt="doxygen"/></a> 1.9.6 </li>
</ul>
</div>
</body>
</html>