下载 FreeRTOS
 

出色的 RTOS & 嵌入式软件

最新资讯
简化任何设备的身份验证云连接。
利用 CoAP 设计节能型云连接 IoT 解决方案。
11.0.0 版 FreeRTOS 内核简介:
FreeRTOS 路线图和代码贡献流程。
使用 FreeRTOS 实现 OPC-UA over TSN。

传输接口

简介

coreMQTTcoreHTTP 不依赖于任何特定的 TCP/IP 堆栈。 因此,您需提供传输接口结构体才能使用 coreMQTT 或 coreHTTP 库。传输接口的实例包含在单个网络连接上发送和接收数据所需的函数指针和上下文数据。FreeRTOS 发行版包括传输接口的示例实现,您可在您的应用程序中使用此实现。

自定义实现

如果示例实现与底层网络或 TLS 堆栈不匹配,则应用程序可提供自身的传输接口实现。一个实现包含两个部分。第一部分是包装底层数据流(例如,套接字句柄或 TLS 上下文)的网络上下文数据结构体的定义。第二部分是一对可在网络上下文中发送和接收数据的函数——这两个函数只包装在具有传输接口结构体所需原型的函数中,您已经用来发送和接收函数的网络。 下文展示了一个有效示例。 传输接口结构体定义如下:


/*

* The NetworkContext is an incomplete type. An implementation of this

* interface must define struct NetworkContext for the system's requirements.

* For example, a plain-text implementation of the NetworkContext type might

* include a socket, and a TLS implementation might add a TLS context. This

* context is passed into the network interface send() and recv() functions.

*/

struct NetworkContext;
typedef struct NetworkContext NetworkContext_t;

/*

* @brief Transport interface for receiving data on the network.

*

* @note It is RECOMMENDED that the transport receive implementation

* does NOT block when requested to read a single byte. A single byte

* read request can be made by the caller to check whether there is a

* new frame available on the network for reading.

* However, the receive implementation MAY block for a timeout period when

* it is requested to read more than 1 byte. This is because once the caller

* is aware that a new frame is available to read on the network, then

* the likelihood of reading more than one byte over the network becomes high.

*

* @param[in, out] pNetworkContext Implementation-defined network context.

* @param[in, out] pBuffer Buffer to receive the data into.

* @param[in] bytesToRecv Number of bytes requested from the network.

*

* @return The number of bytes received or a negative value to indicate

* error.

*

* @note If no data is available on the network to read and no error

* has occurred, zero MUST be the return value. A zero return value

* SHOULD represent that the read operation can be retried by calling

* the API function. Zero MUST NOT be returned if a network disconnection

* has occurred.

*/

typedef int32_t ( * TransportRecv_t )( NetworkContext_t * pNetworkContext,
void * pBuffer,
size_t bytesToRecv );

/*

* @brief Transport interface for sending data over the network.

*

* @note It is RECOMMENDED that a non-fatal failure in transmitting bytes over

* the network, like a full transmit buffer of the underlying TCP stack, is

* treated as a retriable error operation by returning a zero return value.

*

* @param[in, out] pNetworkContext Implementation-defined network context.

* @param[in] pBuffer Buffer containing the bytes to send over the network.

* @param[in] bytesToSend Number of bytes to send over the network.

*

* @return The number of bytes sent or a negative value to indicate error.

*

* @note If no data is transmitted over the network and no network error

* has occurred, this MUST return zero as the return value.

* A zero return value SHOULD represent that the send operation can be retried

* by calling the API function. Zero MUST NOT be returned if a network

* disconnection has occurred.

*/

typedef int32_t ( * TransportSend_t )( NetworkContext_t * pNetworkContext,
const void * pBuffer,
size_t bytesToSend );

/**

* @brief Transport vector structure for sending multiple messages in a single

* packet.

*/

typedef struct TransportOutVector
{
/**

* @brief Base address of data.

*/

const void * iov_base;

/**

* @brief Length of data in buffer.

*/

size_t iov_len;
} TransportOutVector_t;

/*

* @brief Transport interface function for "vectored" / scatter-gather based

* writes. This function is expected to iterate over the list of vectors pIoVec

* having ioVecCount entries containing portions of one MQTT message at a maximum.

* If the proper functionality is available, then the data in the list should be

* copied to the underlying TCP buffer before flushing the buffer. Implementing it

* in this fashion will lead to sending of fewer TCP packets for all the values

* in the list.

*

* @note If the proper write functionality is not present for a given device/IP-stack,

* then there is no strict requirement to implement write. Only the send and recv

* interfaces must be defined for the application to work properly.

*

* @param[in] pNetworkContext Implementation-defined network context.

* @param[in] pIoVec An array of TransportIoVector_t structs.

* @param[in] ioVecCount Number of TransportIoVector_t in pIoVec.

*

* @return The number of bytes written or a negative value to indicate error.

*

* @note If no data is written to the buffer due to the buffer being full this MUST

* return zero as the return value.

* A zero return value SHOULD represent that the write operation can be retried

* by calling the API function. Zero MUST NOT be returned if a network disconnection

* has occurred.

*/

typedef int32_t ( * TransportWritev_t )( NetworkContext_t * pNetworkContext,
TransportOutVector_t * pIoVec,
size_t ioVecCount );
typedef struct TransportInterface
{
TransportRecv_t recv; /* Receive function (see above) */
TransportSend_t send; /* Send function (see above) */
TransportWritev_t writev; /* Writev function (see above) */
NetworkContext_t * pNetworkContext; /* Network context (see above) */
} TransportInterface_t;
传输接口结构体


有效示例

本示例介绍了如何创建适用于 FreeRTOS-Plus-TCP 堆栈的传输接口 (此示例仅作演示之用,FreeRTOS 源代码下载文件已包含适用于 FreeRTOS-Plus-TCP 的传输接口)。 为简单起见,此示例是使用没有 TLS 或其它加密形式的 TCP 。 IoT 生产设备应始终使用加密 连接,而且 FreeRTOS 下载文件中包含使用 带 TLS 堆栈的 FreeRTOS-Plus-TCP 的传输接口

起点

在创建网络传输接口前,请务必确保您的应用程序可以 成功发送和接收网络上的数据—— 如此一来,传输接口仅包装已在运行的发送和接收函数 。

定义 NetworkContext 结构体

FreeRTOS-Plus-TCP 套接字 存储在 Socket_t 类型的变量中。 因此,NetworkContext 结构体 可定义为:

/* The network context just contains the FreeRTOS-Plus-TCP socket 

* (Note: production systems should use TLS, not just the underlying

* socket, so could use the TLS context here instead of the socket) */

struct NetworkContext
{
Socket_t tcpSocket;
};
定义仅包含 FreeRTOS-Plus-TCP 套接字的 NetworkContext 结构体。

实现发送和接收包装器

接下来,FreeRTOS-Plus-TCP 发送接收函数需要 由具有传输接口发送和接收函数所需的原型的函数来包装 。 下述示例还演示了如何 从 NetworkContext 参数中获取发送和接收函数使用的套接字:

/* The prototypes of the following send and receive functions match that

expected by the transport interface's function pointers. These simple

implementations show how to use the network context structure defined

above. */



int32_t transport_recv( NetworkContext_t * pNetworkContext,
void * pBuffer,
size_t bytesToRecv )
{
int32_t socketStatus = 1;

/* The TCP socket may have a receive block time. If bytesToRecv is greater

* than 1, then a frame is likely already part way through reception and

* blocking to wait for the desired number of bytes to be available is the

* most efficient thing to do. If bytesToRecv is 1, then this may be a

* speculative call to read to find the start of a new frame, in which case

* blocking is not desirable as it could block an entire protocol agent

* task for the duration of the read block time and therefore negatively

* impact performance. So if bytesToRecv is 1, then don't call recv unless

* it is known that bytes are already available. */

if( bytesToRecv == 1 )
{
socketStatus = ( int32_t ) FreeRTOS_recvcount( pPlaintextTransportParams->tcpSocket );
}

if( socketStatus > 0 )
{
socketStatus = FreeRTOS_recv( pNetworkContext->tcpSocket, pBuffer, bytesToRecv, 0 );
}

return socketStatus;
}

int32_t transport_send( NetworkContext_t * pNetworkContext,
const void * pBuffer,
size_t bytesToSend )
{
int32_t socketStatus;

socketStatus = FreeRTOS_send( pNetworkContext->tcpSocket, pBuffer, bytesToSend, 0 );

if( socketStatus == -pdFREERTOS_ERRNO_ENOSPC )
{
/* The TCP buffers could not accept any more bytes so zero bytes were sent.

* This is not necessarily an error that should cause a disconnect unless

* it persists so return 0 bytes received rather than an error. */

socketStatus = 0;
}

return socketStatus;
}
实现适用于 FreeRTOS-Plus-TCP 的传输发送和接收函数


填充 TransportInterface_t 结构体

最后,下述代码显示了如何 用 NetworkContext 结构体,以及上文定义的 transport_send () transport_recv () 函数填充传输接口结构体的过程:

/* Populating the TransportInterface_t structure with the definitions above. */
void init_transport_from_socket( Socket_t tcpSocket,
NetworkContext_t * pNetworkContext,
TransportInterface_t * pTransport )
{
pNetworkContext->tcpSocket = tcpSocket;
pTransport->recv = transport_recv;
pTransport->send = transport_send;
/* There is no equivalent writev implementation in FreeRTOS+TCP. */
pTransport->writev = NULL;
pTransport->pNetworkContext = pNetworkContext;
}
定义 transport_interface.h 中声明的网络上下文


示例实现

包括明文通信和 TLS 通信示例。我们强烈建议生产应用程序使用 TLS 进行通信。正如 MQTT TLS 演示所展示的那样,它所提供的传输接口经过身份验证,并被加密过。

FreeRTOS 下载文件中所包含的传输接口实现被拆分为两份文件,一份是 TCP 堆栈专用的包装器 C 文件,另一份是专门针对所选 TCP 堆栈和 TLS 堆栈一起使用情况的 C 补充文件。 例如,若想要一同使用 FreeRTOS-Plus-TCP 和 mbedTLS,请从源代码分发中的 network_transport/freertos_plus_tcp 目录构建 sockets_wrapper.c,然后从 using_mbedtls 子目录构建 using_mbedtls.c

Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.