下载 FreeRTOS
 

出色的 RTOS & 嵌入式软件

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

使用 TCP 套接字(零拷贝接口)发送数据
FreeRTOS-Plus-TCP 联网教程的一部分

请参阅发送 UDP 数据(零复制接口) ,了解关于使用 UDP 零拷贝接口发送数据的内容。

FreeRTOS_send() TCP/IP 堆栈 API 函数用于向 TCP 套接字发送数据。只有在使用 API 函数 创建、配置绑定 套接字并将其连接到远程套接字, 或接受来自远程套接字的连接后 FreeRTOS_connect() 才能发送数据 。

以下源代码片段显示了创建套接字、 通过零拷贝接口向套接字发送数据,然后优雅地关闭套接字的函数。显示的是 IPv4 和 IPv6 用例。 请注意,此套接字未显式绑定到移植号——导致它在 FreeRTOS_connect() API 函数内被自动绑定。

IPv4


void vTCPSend( char *pcBufferToTransmit, const size_t xTotalLengthToSend )
{
Socket_t xSocket;
struct freertos_sockaddr xRemoteAddress;
BaseType_t xAlreadyTransmitted = 0, xBytesSent = 0;
TaskHandle_t xRxTask = NULL;
size_t xLenToSend;

/* Set the IP address (192.168.0.200) and port (1500) of the remote socket

to which this client socket will transmit. */

xRemoteAddress.sin_port = FreeRTOS_htons( 1500 );
xRemoteAddress.sin_addr = FreeRTOS_inet_addr_quick( 192, 168, 0, 200 );

/* Create a socket. */
xSocket = FreeRTOS_socket( FREERTOS_AF_INET,
FREERTOS_SOCK_STREAM, /* FREERTOS_SOCK_STREAM for TCP. */
FREERTOS_IPPROTO_TCP );
configASSERT( xSocket != FREERTOS_INVALID_SOCKET );

/* Connect to the remote socket. The socket has not previously been bound to

a local port number so will get automatically bound to a local port inside

the FreeRTOS_connect() function. */

if( FreeRTOS_connect( xSocket, &xRemoteAddress, sizeof( xRemoteAddress ) ) == 0 )
{
/* Keep sending until the entire buffer has been sent. */
while( xAlreadyTransmitted < xTotalLengthToSend )
{
BaseType_t xAvlSpace = 0;
BaseType_t xBytesToSend = 0;
uint8_t *pucTCPZeroCopyStrmBuffer;

/* This RTOS task is going to send using the zero copy interface. The

data being sent is therefore written directly into the TCP TX stream

buffer that is passed into, rather than copied into, the FreeRTOS_send()

function. */


/* Obtain the pointer to the current head of sockets TX stream buffer

using FreeRTOS_get_tx_head */

pucTCPZeroCopyStrmBuffer = FreeRTOS_get_tx_head( xSocket, &xAvlSpace );

if(pucTCPZeroCopyStrmBuffer)
{
/* Check if there is enough space in the stream buffer to place

the entire data. */

if((xTotalLengthToSend - xAlreadyTransmitted) > xAvlSpace)
{
xBytesToSend = xAvlSpace;
}
else
{
xBytesToSend = (xTotalLengthToSend - xAlreadyTransmitted);
}
memcpy( pucTCPZeroCopyStrmBuffer,
( void * ) (( (uint8_t *) pcBufferToTransmit ) + xAlreadyTransmitted),
xBytesToSend);
}
else
{
/* Error - break out of the loop for graceful socket close. */
break;
}

/* Call the FreeRTOS_send with buffer as NULL indicating to the stack

that its a zero copy */

xBytesSent = FreeRTOS_send( /* The socket being sent to. */
xSocket,
/* The data being sent. */
NULL,
/* The remaining length of data to send. */
xBytesToSend,
/* ulFlags. */
0 );

if( xBytesSent >= 0 )
{
/* Data was sent successfully. */
xAlreadyTransmitted += xBytesSent;
}
else
{
/* Error - break out of the loop for graceful socket close. */
break;
}
}
}

/* Initiate graceful shutdown. */
FreeRTOS_shutdown( xSocket, FREERTOS_SHUT_RDWR );

/* Wait for the socket to disconnect gracefully (indicated by FreeRTOS_recv()

returning a -pdFREERTOS_ERRNO_EINVAL error) before closing the socket. */

while( FreeRTOS_recv( xSocket, pcBufferToTransmit, xTotalLengthToSend, 0 ) >= 0 )
{
/* Wait for shutdown to complete. If a receive block time is used then

this delay will not be necessary as FreeRTOS_recv() will place the RTOS task

into the Blocked state anyway. */

vTaskDelay( pdTICKS_TO_MS( 250 ) );

/* Note - real applications should implement a timeout here, not just

loop forever. */

}

/* The socket has shut down and is safe to close. */
FreeRTOS_closesocket( xSocket );
}

IPv4 Example using FreeRTOS_send() with the zero copy calling semantics

IPv6


void vTCPSend( char *pcBufferToTransmit, const size_t xTotalLengthToSend )
{
Socket_t xSocket;
struct freertos_sockaddr xRemoteAddress;
BaseType_t xAlreadyTransmitted = 0, xBytesSent = 0;
TaskHandle_t xRxTask = NULL;
size_t xLenToSend;

/* Set the IP address (2001:470:ed44::9c08:38cc:599f:f62a) and port (1500) of the remote socket

to which this client socket will transmit. */

xRemoteAddress.sin_port = FreeRTOS_htons( 1500 );
FreeRTOS_inet_pton6( "2001:470:ed44::9c08:38cc:599f:f62a",
(void *) xRemoteAddress.sin_address.xIP_IPv6.ucBytes )

/* Create a socket. */
xSocket = FreeRTOS_socket( FREERTOS_AF_INET6,
FREERTOS_SOCK_STREAM, /* FREERTOS_SOCK_STREAM for TCP. */
FREERTOS_IPPROTO_TCP );
configASSERT( xSocket != FREERTOS_INVALID_SOCKET );

/* Connect to the remote socket. The socket has not previously been bound to

a local port number so will get automatically bound to a local port inside

the FreeRTOS_connect() function. */

if( FreeRTOS_connect( xSocket, &xRemoteAddress, sizeof( xRemoteAddress ) ) == 0 )
{
/* Keep sending until the entire buffer has been sent. */
while( xAlreadyTransmitted < xTotalLengthToSend )
{
BaseType_t xAvlSpace = 0;
BaseType_t xBytesToSend = 0;
uint8_t *pucTCPZeroCopyStrmBuffer;

/* This RTOS task is going to send using the zero copy interface. The

data being sent is therefore written directly into the TCP TX stream

buffer that is passed into, rather than copied into, the FreeRTOS_send()

function. */


/* Obtain the pointer to the current head of sockets TX stream buffer

using FreeRTOS_get_tx_head */

pucTCPZeroCopyStrmBuffer = FreeRTOS_get_tx_head( xSocket, &xAvlSpace );

if(pucTCPZeroCopyStrmBuffer)
{
/* Check of there is enough space in the stream buffer to place

the entire data. */

if((xTotalLengthToSend - xAlreadyTransmitted) > xAvlSpace)
{
xBytesToSend = xAvlSpace;
}
else
{
xBytesToSend = (xTotalLengthToSend - xAlreadyTransmitted);
}
memcpy( pucTCPZeroCopyStrmBuffer,
( void * ) (( (uint8_t *) pcBufferToTransmit ) + xAlreadyTransmitted),
xBytesToSend);
}
else
{
/* Error - break out of the loop for graceful socket close. */
break;
}

/* Call the FreeRTOS_send with buffer as NULL indicating to the stack

that its a zero copy */

xBytesSent = FreeRTOS_send( /* The socket being sent to. */
xSocket,
/* The data being sent. */
NULL,
/* The remaining length of data to send. */
xBytesToSend,
/* ulFlags. */
0 );

if( xBytesSent >= 0 )
{
/* Data was sent successfully. */
xAlreadyTransmitted += xBytesSent;
}
else
{
/* Error - break out of the loop for graceful socket close. */
break;
}
}
}

/* Initiate graceful shutdown. */
FreeRTOS_shutdown( xSocket, FREERTOS_SHUT_RDWR );

/* Wait for the socket to disconnect gracefully (indicated by FreeRTOS_recv()

returning a -pdFREERTOS_ERRNO_EINVAL error) before closing the socket. */

while( FreeRTOS_recv( xSocket, pcBufferToTransmit, xTotalLengthToSend, 0 ) >= 0 )
{
/* Wait for shutdown to complete. If a receive block time is used then

this delay will not be necessary as FreeRTOS_recv() will place the RTOS task

into the Blocked state anyway. */

vTaskDelay( pdTICKS_TO_MS( 250 ) );

/* Note - real applications should implement a timeout here, not just

loop forever. */

}

/* The socket has shut down and is safe to close. */
FreeRTOS_closesocket( xSocket );
}

IPv6 Example using FreeRTOS_send() with the zero copy calling semantics

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