Part 1
요약·해설
MQTT 3.1/3.1.1 client context, non-blocking input loop, connection upkeep와 TLS credential 설정을 설명합니다.
Publish · Subscribe
TCP · TLS
3.1 · 3.1.1
Part 2
접을 수 있는 영어 원문 전체
영어 원문 전체 펼치기
E93C8B918C139CB8AD096024B6A8BDD81215EF027A0E076D91AE771CA9CE6DB9
.. _mqtt_socket_interface:
MQTT
####
.. contents::
:local:
:depth: 2
Overview
********
MQTT (Message Queuing Telemetry Transport) is an application layer protocol
which works on top of the TCP/IP stack. It is a lightweight
publish/subscribe messaging transport for machine-to-machine communication.
For more information about the protocol itself, see http://mqtt.org/.
Zephyr provides an MQTT client library built on top of BSD sockets API. The
library can be enabled with :kconfig:option:`CONFIG_MQTT_LIB` Kconfig option and
is configurable at a per-client basis, with support for MQTT versions
3.1.0 and 3.1.1. The Zephyr MQTT implementation can be used with either plain
sockets communicating over TCP, or with secure sockets communicating over
TLS. See :ref:`bsd_sockets_interface` for more information about Zephyr sockets.
MQTT clients require an MQTT server to connect to. Such a server, called an MQTT Broker,
is responsible for managing client subscriptions and distributing messages
published by clients. There are many implementations of MQTT brokers, one of them
being Eclipse Mosquitto. See https://mosquitto.org/ for more information about
the Eclipse Mosquitto project.
Sample usage
************
To create an MQTT client, a client context structure and buffers need to be
defined:
.. code-block:: c
/* Buffers for MQTT client. */
static uint8_t rx_buffer[256];
static uint8_t tx_buffer[256];
/* MQTT client context */
static struct mqtt_client client_ctx;
Multiple MQTT client instances can be created in the application and managed
independently. Additionally, a structure for MQTT Broker address information
is needed. This structure must be accessible throughout the lifespan
of the MQTT client and can be shared among MQTT clients:
.. code-block:: c
/* MQTT Broker address information. */
static struct sockaddr_storage broker;
An MQTT client library will notify MQTT events to the application through a
callback function created to handle respective events:
.. code-block:: c
void mqtt_evt_handler(struct mqtt_client *client,
const struct mqtt_evt *evt)
{
switch (evt->type) {
/* Handle events here. */
}
}
For a list of possible events, see :ref:`mqtt_api_reference`.
The client context structure needs to be initialized and set up before it can be
used. An example configuration for TCP transport is shown below:
.. code-block:: c
mqtt_client_init(&client_ctx);
/* MQTT client configuration */
client_ctx.broker = &broker;
client_ctx.evt_cb = mqtt_evt_handler;
client_ctx.client_id.utf8 = (uint8_t *)"zephyr_mqtt_client";
client_ctx.client_id.size = sizeof("zephyr_mqtt_client") - 1;
client_ctx.password = NULL;
client_ctx.user_name = NULL;
client_ctx.protocol_version = MQTT_VERSION_3_1_1;
client_ctx.transport.type = MQTT_TRANSPORT_NON_SECURE;
/* MQTT buffers configuration */
client_ctx.rx_buf = rx_buffer;
client_ctx.rx_buf_size = sizeof(rx_buffer);
client_ctx.tx_buf = tx_buffer;
client_ctx.tx_buf_size = sizeof(tx_buffer);
After the configuration is set up, the MQTT client can connect to the MQTT broker.
Call the ``mqtt_connect`` function, which will create the appropriate socket,
establish a TCP/TLS connection, and send an ``MQTT CONNECT`` message.
When notified, the application should call the ``mqtt_input`` function to process
the response received. Note, that ``mqtt_input`` is a non-blocking function,
therefore the application should use socket ``poll`` to wait for the response.
If the connection was successful, ``MQTT_EVT_CONNACK`` will be notified to the
application through the callback function.
.. code-block:: c
rc = mqtt_connect(&client_ctx);
if (rc != 0) {
return rc;
}
fds[0].fd = client_ctx.transport.tcp.sock;
fds[0].events = ZSOCK_POLLIN;
poll(fds, 1, 5000);
mqtt_input(&client_ctx);
if (!connected) {
mqtt_abort(&client_ctx);
}
In the above code snippet, the MQTT callback function should set the ``connected``
flag upon a successful connection. If the connection fails at the MQTT level
or a timeout occurs, the connection will be aborted, and the underlying socket
closed.
After the connection is established, an application needs to call ``mqtt_input``
and ``mqtt_live`` functions periodically to process incoming data and upkeep
the connection. If an MQTT message is received, an MQTT callback function will
be called and an appropriate event notified.
The connection can be closed by calling the ``mqtt_disconnect`` function.
Zephyr provides sample code utilizing the MQTT client API. See
:zephyr:code-sample:`mqtt-publisher` for more information.
Using MQTT with TLS
*******************
The Zephyr MQTT library can be used with TLS transport for secure communication
by selecting a secure transport type (``MQTT_TRANSPORT_SECURE``) and some
additional configuration information:
.. code-block:: c
client_ctx.transport.type = MQTT_TRANSPORT_SECURE;
struct mqtt_sec_config *tls_config = &client_ctx.transport.tls.config;
tls_config->peer_verify = TLS_PEER_VERIFY_REQUIRED;
tls_config->cipher_list = NULL;
tls_config->sec_tag_list = m_sec_tags;
tls_config->sec_tag_count = ARRAY_SIZE(m_sec_tags);
tls_config->hostname = MQTT_BROKER_HOSTNAME;
In this sample code, the ``m_sec_tags`` array holds a list of tags, referencing TLS
credentials that the MQTT library should use for authentication. We do not specify
``cipher_list``, to allow the use of all cipher suites available in the system.
We set ``hostname`` field to broker hostname, which is required for server
authentication. Finally, we enforce peer certificate verification by setting
the ``peer_verify`` field.
Note, that TLS credentials referenced by the ``m_sec_tags`` array must be
registered in the system first. For more information on how to do that, refer
to :ref:`secure sockets documentation <secure_sockets_interface>`.
An example of how to use TLS with MQTT is also present in
:zephyr:code-sample:`mqtt-publisher` sample application.
.. _mqtt_api_reference:
API Reference
*************
.. doxygengroup:: mqtt_socket
Part 3
한국어 전문 번역
MQTT
Overview
MQTT(Message Queuing Telemetry Transport)는 TCP/IP stack 위에서 동작하는 application-layer protocol입니다. Machine-to-machine communication을 위한 lightweight publish/subscribe messaging transport이며 자세한 protocol 정보는 mqtt.org에 있습니다.
Zephyr는 BSD socket API 위에 구현한 MQTT client library를 제공합니다. CONFIG_MQTT_LIB Kconfig option으로 활성화하고 client별로 설정할 수 있으며 MQTT 3.1.0과 3.1.1을 지원합니다. Plain socket의 TCP 또는 secure socket의 TLS를 사용할 수 있습니다.
MQTT client가 연결하려면 MQTT server가 필요합니다. MQTT Broker라고 부르는 server는 client subscription을 관리하고 client가 publish한 message를 배포합니다. Broker 구현 가운데 하나는 Eclipse Mosquitto입니다.
Sample usage
MQTT client를 만들려면 client context structure와 buffer를 정의합니다.
/* Buffers for MQTT client. */
static uint8_t rx_buffer[256];
static uint8_t tx_buffer[256];
/* MQTT client context */
static struct mqtt_client client_ctx;Application에서 MQTT client instance를 여러 개 만들어 독립적으로 관리할 수 있습니다. MQTT Broker address information structure도 필요합니다. 이 structure는 MQTT client의 전체 lifespan 동안 접근 가능해야 하며 여러 client가 공유할 수 있습니다.
/* MQTT Broker address information. */
static struct sockaddr_storage broker;MQTT client library는 event callback을 통해 application에 MQTT event를 알립니다.
void mqtt_evt_handler(struct mqtt_client *client,
const struct mqtt_evt *evt)
{
switch (evt->type) {
/* Handle events here. */
}
}가능한 event 목록은 MQTT API reference에서 확인할 수 있습니다.
Client context structure는 사용 전에 initialize하고 설정해야 합니다. 다음은 TCP transport configuration 예입니다.
mqtt_client_init(&client_ctx);
/* MQTT client configuration */
client_ctx.broker = &broker;
client_ctx.evt_cb = mqtt_evt_handler;
client_ctx.client_id.utf8 = (uint8_t *)"zephyr_mqtt_client";
client_ctx.client_id.size = sizeof("zephyr_mqtt_client") - 1;
client_ctx.password = NULL;
client_ctx.user_name = NULL;
client_ctx.protocol_version = MQTT_VERSION_3_1_1;
client_ctx.transport.type = MQTT_TRANSPORT_NON_SECURE;
/* MQTT buffers configuration */
client_ctx.rx_buf = rx_buffer;
client_ctx.rx_buf_size = sizeof(rx_buffer);
client_ctx.tx_buf = tx_buffer;
client_ctx.tx_buf_size = sizeof(tx_buffer);mqtt_client_init() 뒤 broker, event callback, client ID, optional password·user name, protocol version을 설정합니다. MQTT_TRANSPORT_NON_SECURE를 선택하고 RX·TX buffer와 크기를 지정합니다.
mqtt_connect()를 호출하면 적절한 socket을 만들고 TCP 또는 TLS connection을 설정한 뒤 MQTT CONNECT message를 보냅니다. Response가 도착했다는 알림을 받으면 application이 mqtt_input()을 호출해 처리해야 합니다. 이 함수는 non-blocking이므로 socket poll()로 response를 기다립니다. Connection에 성공하면 callback으로 MQTT_EVT_CONNACK event가 전달됩니다.
rc = mqtt_connect(&client_ctx);
if (rc != 0) {
return rc;
}
fds[0].fd = client_ctx.transport.tcp.sock;
fds[0].events = ZSOCK_POLLIN;
poll(fds, 1, 5000);
mqtt_input(&client_ctx);
if (!connected) {
mqtt_abort(&client_ctx);
}위 예에서 callback은 connection 성공 시 connected flag를 설정해야 합니다. MQTT level connection failure 또는 timeout이 발생하면 mqtt_abort()로 connection을 중단하고 underlying socket을 닫습니다.
mqtt_input()과 mqtt_live()를 주기적으로 호출해 incoming data를 처리하고 connection을 유지해야 합니다. MQTT message가 도착하면 callback이 호출되고 해당 event가 전달됩니다.
mqtt_disconnect()를 호출해 connection을 닫을 수 있습니다.
mqtt-publisher sample에서 MQTT client API 사용 code를 확인할 수 있습니다.
Using MQTT with TLS
MQTT_TRANSPORT_SECURE transport type과 추가 configuration을 선택하면 TLS로 MQTT communication을 보호할 수 있습니다.
client_ctx.transport.type = MQTT_TRANSPORT_SECURE;
struct mqtt_sec_config *tls_config = &client_ctx.transport.tls.config;
tls_config->peer_verify = TLS_PEER_VERIFY_REQUIRED;
tls_config->cipher_list = NULL;
tls_config->sec_tag_list = m_sec_tags;
tls_config->sec_tag_count = ARRAY_SIZE(m_sec_tags);
tls_config->hostname = MQTT_BROKER_HOSTNAME;m_sec_tags array에는 MQTT library가 authentication에 사용할 TLS credential tag 목록이 있습니다. cipher_list를 지정하지 않아 system의 모든 cipher suite를 허용합니다. Server authentication에 필요한 broker hostname을 hostname에 넣고 peer_verify로 peer certificate verification을 강제합니다.
m_sec_tags가 참조하는 TLS credential은 먼저 system에 등록해야 합니다. 등록 방법은 secure sockets 문서를 참고합니다.
mqtt-publisher sample에도 MQTT TLS 사용 예가 있습니다.
API Reference
Doxygen group mqtt_socket이 API reference를 제공합니다.
Source
출처
영어 원문에는 문단, 문서 지시문, 표, 코드, 코드 심벌, 경로를 그대로 보존했습니다.