

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 安全套接字库
<a name="secure-sockets"></a>

**重要**  <a name="deprecation-message-library"></a>
该库托管在已弃用的 Amazon-FreeRTOS 存储库中。当您创建新项目时，我们建议[从此处开始](freertos-getting-started-modular.md)。如果您已经有一个基于现已弃用的 Amazon-FreeRTOS 存储库的 FreeRTOS 项目，请参阅 [Amazon-FreeRTOS Github 存储库迁移指南](github-repo-migration.md)。

## 概述
<a name="freertos-secure-sockets-overview"></a>

您可以使用 FreeRTOS [安全套接字](https://docs.amazonaws.cn/freertos/latest/lib-ref/html2/secure_sockets/index.html)库来创建可安全通信的嵌入式应用程序。该库旨在使来自各种网络编程背景的软件开发人员能够轻松掌握。

FreeRTOS 安全套接字库基于 Berkeley 套接字接口，并具有通过 TLS 协议进行安全通信的额外选项。有关 FreeRTOS 安全套接字库和 Berkeley 套接字接口之间差异的信息，请参阅[安全套接字 API 参考](https://docs.amazonaws.cn/freertos/latest/lib-ref/html2/secure_sockets/index.html)中的 `SOCKETS_SetSockOpt`。

**注意**  
目前，Free [RTOS 安全套接字仅支持客户端 APIs，再加上服务器`Bind`端 API 的轻量级 IP (LW](https://savannah.nongnu.org/projects/lwip/) IP) 实现。

## 依赖项和要求
<a name="freertos-secure-sockets-dependencies"></a>

FreeRTOS 安全套接字库依赖于堆栈和 T TCP/IP LS 实现。FreeRTOS 的端口通过三种方式之一来满足这些依赖项：
+ 两者兼而有之 TLS TCP/IP 的自定义实现
+ TCP/IP 以及具有 [mbedTLS](https://en.wikipedia.org/wiki/Mbed_TLS) 的 FreeRTOS TLS 层的自定义实现
+ [FreeRTOS\+TCP](https://freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/index.html) 和具有 [mbedTLS](https://en.wikipedia.org/wiki/Mbed_TLS) 的 FreeRTOS TLS 层

以下依赖项图显示了 FreeRTOS 安全套接字库包含的参考实施。此参考实现支持 TLS、以太网和 TCP/IP Wi-Fi，并以 freerTOS\+TCP 和 mbedTLS 为依赖项。有关 FreeRTOS TLS 层的更多信息，请参阅[传输层安全](security-tls.md)。

![包含 FreeRTOS+TCP、TLS 层和 TLS 组件的安全套接字库架构。](http://docs.amazonaws.cn/freertos/latest/userguide/images/sockets-dependencies.png)


## 功能
<a name="freertos-secure-sockets-features"></a>

FreeRTOS 安全套接字库的功能包括：
+ 一个基于 Berkeley 套接字的标准接口
+ 线程安全 APIs ，用于发送和接收数据
+ Easy-to-enable TLS

## 问题排查
<a name="freertos-secure-sockets-troubleshooting"></a>

### 错误代码
<a name="w2aac31b9c13c45c15b5"></a>

FreeRTOS 安全套接字库返回的错误代码为负值。有关每个错误代码的更多信息，请参阅[安全套接字 API 参考](https://docs.amazonaws.cn/freertos/latest/lib-ref/html2/secure_sockets/index.html)中的安全套接字错误代码。

**注意**  
如果 FreeRTOS 安全套接字 API 返回错误代码，则 [coreMQTT 库](coremqtt.md)（依赖于 FreeRTOS 安全套接字库）返回错误代码 `AWS_IOT_MQTT_SEND_ERROR`。

## 开发人员支持
<a name="freertos-secure-sockets-support"></a>

FreeRTOS 安全套接字库包含两个用于处理 IP 地址的辅助标记宏：

**`SOCKETS_inet_addr_quick`**  
此宏将表示为四个独立数字八位字节的 IP 地址转换为按网络字节顺序表示为 32 位数字的 IP 地址。

**`SOCKETS_inet_ntoa`**  
此宏将按网络字节顺序表示为 32 位数字的 IP 地址转换为用十进制表示的字符串。

## 使用限制
<a name="freertos-secure-sockets-restrictions"></a>

FreeRTOS 安全套接字库仅支持 TCP 套接字。不支持 UDP 套接字。

除了服务器端 APIs API 的轻量级 [IP (LWIP)](https://savannah.nongnu.org/projects/lwip/) 实现之外，FreeRTOS 安全套接字库不支持服务器。`Bind`支持 APIs 客户端。

## 初始化
<a name="freertos-secure-sockets-initialization"></a>

要使用 FreeRTOS 安全套接字库，您需要初始化该库及其依赖项。要初始化安全套接字库，请在应用程序中使用以下代码：

```
BaseType_t xResult = pdPASS;
xResult = SOCKETS_Init();
```

必须单独初始化相关库。例如，如果 FreeRTOS\+TCP 是一个依赖项，则您还需要在应用程序中调用 [https://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/API/FreeRTOS_IPInit.html](https://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/API/FreeRTOS_IPInit.html)。

## API 参考
<a name="freertos-secure-sockets-api"></a>

有关完整 API 参考，请参阅[安全套接字 API 参考](https://docs.amazonaws.cn/freertos/latest/lib-ref/html2/secure_sockets/index.html)。

## 示例用法
<a name="freertos-secure-sockets-example"></a>

以下代码可将客户端连接到服务器。

```
#include "aws_secure_sockets.h"

#define configSERVER_ADDR0                     127
#define configSERVER_ADDR1                     0
#define configSERVER_ADDR2                     0
#define configSERVER_ADDR3                     1
#define configCLIENT_PORT                      443

/* Rx and Tx timeouts are used to ensure the sockets do not wait too long for
 * missing data. */
static const TickType_t xReceiveTimeOut = pdMS_TO_TICKS( 2000 );
static const TickType_t xSendTimeOut = pdMS_TO_TICKS( 2000 );

/* PEM-encoded server certificate */
/* The certificate used below is one of the Amazon Root CAs.\
Change this to the certificate of your choice. */
static const char cTlsECHO_SERVER_CERTIFICATE_PEM[] =
"-----BEGIN CERTIFICATE-----\n"
"MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5\n"
"MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g\n"
"Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG\n"
"A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg\n"
"Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl\n"
"ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j\n"
"QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr\n"
"ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr\n"
"BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM\n"
"YyRIHN8wfdVoOw==\n"
"-----END CERTIFICATE-----\n";

static const uint32_t ulTlsECHO_SERVER_CERTIFICATE_LENGTH = sizeof( cTlsECHO_SERVER_CERTIFICATE_PEM );

void vConnectToServerWithSecureSocket( void )
{
    Socket_t xSocket;
    SocketsSockaddr_t xEchoServerAddress;
    BaseType_t xTransmitted, lStringLength;

    xEchoServerAddress.usPort = SOCKETS_htons( configCLIENT_PORT );
    xEchoServerAddress.ulAddress = SOCKETS_inet_addr_quick( configSERVER_ADDR0,
                                                            configSERVER_ADDR1,
                                                            configSERVER_ADDR2,
                                                            configSERVER_ADDR3 );
                                                            
    /* Create a TCP socket. */
    xSocket = SOCKETS_Socket( SOCKETS_AF_INET, SOCKETS_SOCK_STREAM, SOCKETS_IPPROTO_TCP );
    configASSERT( xSocket != SOCKETS_INVALID_SOCKET );
    
    /* Set a timeout so a missing reply does not cause the task to block indefinitely. */
    SOCKETS_SetSockOpt( xSocket, 0, SOCKETS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof( xReceiveTimeOut ) );
    SOCKETS_SetSockOpt( xSocket, 0, SOCKETS_SO_SNDTIMEO, &xSendTimeOut, sizeof( xSendTimeOut ) );

    /* Set the socket to use TLS. */
    SOCKETS_SetSockOpt( xSocket, 0, SOCKETS_SO_REQUIRE_TLS, NULL, ( size_t ) 0 );
    SOCKETS_SetSockOpt( xSocket, 0, SOCKETS_SO_TRUSTED_SERVER_CERTIFICATE, cTlsECHO_SERVER_CERTIFICATE_PEM, ulTlsECHO_SERVER_CERTIFICATE_LENGTH );

    if( SOCKETS_Connect( xSocket, &xEchoServerAddress, sizeof( xEchoServerAddress ) ) == 0 )
    {
        /* Send the string to the socket. */
        xTransmitted = SOCKETS_Send( xSocket,                         /* The socket receiving. */
                                     ( void * )"some message",        /* The data being sent. */
                                     12,                              /* The length of the data being sent. */
                                     0 );                             /* No flags. */

        if( xTransmitted < 0 )
        {
            /* Error while sending data */
            return;
        }

        SOCKETS_Shutdown( xSocket, SOCKETS_SHUT_RDWR );
    }
    else
    {
        //failed to connect to server
    }

    SOCKETS_Close( xSocket );
}
```

有关完整示例，请参阅[安全套接字 Echo 客户端演示](secure-sockets-demo.md)。

## 移植
<a name="freertos-secure-sockets-porting"></a>

FreeRTOS 安全套接字依赖于堆栈和 T TCP/IP LS 实现。根据您的堆栈，要移植安全套接字库，您可能需要移植以下项目中的部分项目：
+ [freer](https://freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/index.html) TCP/IP tos\+TCP 堆栈
+ 这些区域有：[核心PKCS11 库](security-pkcs.md)
+ 这些区域有：[传输层安全](security-tls.md)

有关移植的更多信息，请参阅《FreeRTOS 移植指南》中的[移植安全套接字库](https://docs.amazonaws.cn/freertos/latest/portingguide/afr-porting-ss.html)。