FreeRTOS+TCP TCP服务器实验

  1. FreeRTOS的套接字绑定函数

函数原型:

BaseType_t FreeRTOS_bind( Socket_t xSocket, struct freertos_sockaddr *pxAddress, socklen_t xAddressLength );

将套接字绑定到本地端口号。绑定套接字将套接字与本地IP地址上的端口号相关联,从而使套接字接收发送到该IP地址的所有数据和端口号组合。

参数描述:

xSocket:目标套接字,该套接字必须由FreeRTOS_socket()创建。

*pxAddress:指向FreeRTOS_sockaddr结构的指针,该结构包含端口的详细信息。

xAddressLength:该参数未使用。

返回值:

绑定成功返回0,如果绑定失败返回FreeRTOS_EINVAL,如果调用的任务没有从任务获得对绑定请求的响应,则返回FreeRTOS_ECANCELED。

  1. FreeRTOS的套接字侦听状态设置函数

函数原型:

BaseType_t FreeRTOS_listen( Socket_t xSocket, BaseType_t xBacklog );

将TCP套接字置于它正在侦听的状态,并可以接受来自远程套接字的传入连接请求。调用前必须调用绑定端口函数绑定相关端口。默认情况下,将创建一个新套接字(子套接字)来处理任何可接受的连接。新套接字将由FreeRTOS_Accept(),可以立即使用。子套接字继承父套接字的所有属性。也可以选择地将FREERTOS_SO_REUSE_LISTEN_SOCKET设置为参数,用于调用FreeRTOS_setsockopt()配置父套接字,以处理任何可接受的连接本身,而不为此创建子套接字。当套接字一次只处理一个连接时,这是一种节省资源的有用方法。

参数描述:

xSocket:目标套接字,该套接字必须由FreeRTOS_socket()创建,并绑定到端口。

xBacklog:在为每个新连接创建新套接字情况下,此参数配置了同时连接的客户端的数量。

返回值:

如果设置成功返回0。如果套接字不是有效套接字则返回pdFREERTOS_ERRNO_EOPNOTSUPP。如果套接字处于未绑定状态则返回pdFREERTOS_ERRNO_EOPNOTSUPP。

  1. FreeRTOS的套接字连接接收函数

函数原型:

Socket_t FreeRTOS_accept( Socket_t xServerSocket, struct freertos_sockaddr *pxAddress, socklen_t *pxAddressLength );

接受TCP套接字上的连接。调用前必须调用绑定端口函数绑定相关端口。

参数描述:

xServerSocket:要接受新连接的侦听套接字的句柄。

*pxAddress:指向FreeRTOS_sockaddr结构的指针,该结构将由接受连接的套接字的IP地址和端口号填充。

*pxAddressLength:该参数未使用。

返回值:

如果接受来自远程套接字的连接,并创建一个新的本地套接字来处理接受的连接则返回到新套接字的句柄。如果xServerSocket不是有效的TCP套接字则返回FreeRTOS_VALID_SOCKET。如果xServerSocket没有处于侦听状态则然后返回FreeRTOS_VALID_SOCKET。如果在接受来自远程套接字的连接之前发生超时,则返回NULL。

 

部分代码  详情参考源码。

#include "TCP_Server.h"

 // 定义端口
#define tcpechoPORT_NUMBER		6902

ClientSocketList_t *pClientSocketHead;
Socket_t xListeningSocket;
struct freertos_sockaddr xBindAddress;
Recivebuff recivebuffed;
uint8_t statut_close = 0;

void prvConnectionListeningTask( void *pvParameters );
void prvServerConnectionInstance( void *pvParameters );
BaseType_t prvClientSocketListDel( Socket_t xDelSocket);
void prvClientSocketListDelALL( void );
void prvClientSocketListAdd( Socket_t xNewSocket);
void prvClientSockeDisconnectionALL( void );

char txdata[] = "The connection was successful!";

 // Server开启函数
void prvSimpleServerOpen(void)
{
	static const TickType_t xReceiveTimeOut = portMAX_DELAY;
	const BaseType_t xBacklog = 20;
	
	// 清空链表
	pClientSocketHead = NULL;
	
	//创建套接字
	xListeningSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP );
	configASSERT( xListeningSocket != FREERTOS_INVALID_SOCKET );
	
	// 设置套接字
	FreeRTOS_setsockopt( xListeningSocket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof( xReceiveTimeOut ) );
	
	// 填充本地端口
	xBindAddress.sin_port = FreeRTOS_htons(tcpechoPORT_NUMBER);
	
	// 绑定端口
	FreeRTOS_bind( xListeningSocket, &xBindAddress, sizeof( xBindAddress ) );
	
	// 设置套接字处于侦听状态
	FreeRTOS_listen( xListeningSocket, xBacklog );
	
	statut_close = 0;
	xTaskCreate( prvConnectionListeningTask, "ServerListener", 520, NULL, 5, NULL );
}

 // Server关闭函数
void prvSimpleServerClose(void)
{
	//强制下线全部客户端
	prvClientSockeDisconnectionALL();
	//清空链表
	prvClientSocketListDelALL();
	
	// 关闭连接
	FreeRTOS_shutdown( xListeningSocket, FREERTOS_SHUT_RDWR );
	
	// 关闭套接字
	FreeRTOS_closesocket( xListeningSocket );
	statut_close = 1;
}

 // 发送函数
uint8_t prvSimpleServerSend(char *pSendBuff,uint32_t lBuffLen)
{	
	BaseType_t lTransmitted;
	ClientSocketList_t *pClientList = pClientSocketHead;
	
	if(pClientList->xClientSocket != NULL)
	{
		lTransmitted = FreeRTOS_send(	pClientList->xClientSocket,pSendBuff,lBuffLen,0 );
		vTaskDelay(1500 / portTICK_PERIOD_MS);
	}
	
	if(lTransmitted < 0)
	{
		return 0;
	}
	else
	{
		return 1;
	}
}

 // 接收函数
void prvSimpleServerRecive(void)
{
	BaseType_t lrecive;
	ClientSocketList_t *pClientList = pClientSocketHead;
	
	lrecive = FreeRTOS_recv(pClientList->xClientSocket,recivebuffed.cRxBuffers,echoBUFFER_SIZES,0);
	if(lrecive <= 0 )
		recivebuffed.length = 0;
	else
	{
		recivebuffed.length = lrecive;
	}
}

 // 接收新连接的套接字
void prvConnectionListeningTask( void *pvParameters )
{
	Socket_t xConnectedSocket;
	struct freertos_sockaddr xClient;
	socklen_t xSize = sizeof( xClient );
	
	while(1)
	{
		if (statut_close == 1)
			vTaskDelete(NULL);
		xConnectedSocket = FreeRTOS_accept( xListeningSocket, &xClient, &xSize );
		configASSERT( xConnectedSocket != FREERTOS_INVALID_SOCKET );
		xTaskCreate( prvServerConnectionInstance, "EchoServer", 520, ( void * ) xConnectedSocket, 4, NULL );
	}
}

 // 记录连接信息
void prvServerConnectionInstance( void *pvParameters )
{
	Socket_t xConnectedSocket;
	static const TickType_t xReceiveTimeOut = pdMS_TO_TICKS( 1000 );
	static const TickType_t xSendTimeOut = pdMS_TO_TICKS( 1000 );
	
	xConnectedSocket = ( Socket_t ) pvParameters;

	FreeRTOS_setsockopt( xConnectedSocket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof( xReceiveTimeOut ) );
	FreeRTOS_setsockopt( xConnectedSocket, 0, FREERTOS_SO_SNDTIMEO, &xSendTimeOut, sizeof( xReceiveTimeOut ) );
	prvClientSocketListAdd(xConnectedSocket);
	
	prvSimpleServerSend(txdata,sizeof(txdata));
	vTaskDelete( NULL );
}

// 链表添加一个
void prvClientSocketListAdd( Socket_t xNewSocket)
{
	if(pClientSocketHead ==NULL)
	{
		pClientSocketHead = (ClientSocketList_t *)pvPortMalloc(sizeof(ClientSocketList_t));
		pClientSocketHead->xClientSocket = xNewSocket;
		pClientSocketHead->pNextClientSocket = NULL;
	}
	else
	{
		ClientSocketList_t *pAddNode = (ClientSocketList_t *)pvPortMalloc(sizeof(ClientSocketList_t));
		pAddNode->pNextClientSocket = pClientSocketHead;
		pAddNode->xClientSocket = xNewSocket;
		pClientSocketHead = pAddNode;
	}
}

 // 链表删除一个
BaseType_t prvClientSocketListDel( Socket_t xDelSocket)
{
	ClientSocketList_t *pNode = pClientSocketHead;
	ClientSocketList_t *pNodeold = NULL;
	if(pNode->pNextClientSocket == NULL)
	{
		if(pNode->xClientSocket == xDelSocket)
		{
			vPortFree(pNode);
			return pdTRUE;
		}
		else
			return pdFALSE;
	}
	else
	{
		while(pNode->xClientSocket != NULL)
		{
			if(pNode->xClientSocket == xDelSocket)
			{
				if(pNodeold == NULL)
				{
					pNode = pNode->pNextClientSocket;
					vPortFree(pNode->pNextClientSocket);
					return pdTRUE;
				}
				else
				{
					pNodeold ->pNextClientSocket =pNode->pNextClientSocket;
					vPortFree(pNode);
					return pdTRUE;
				}
			}
			pNodeold = pNode;
			pNode = pNode->pNextClientSocket;
		}
		return pdFALSE;
	}
}

 // 删除全部链表
void prvClientSocketListDelALL( void )
{
	ClientSocketList_t *pNode = pClientSocketHead;
	
	do
	{
		pClientSocketHead = pNode -> pNextClientSocket;
		vPortFree(pNode);
		pNode = pClientSocketHead->pNextClientSocket;
	}
	while(pClientSocketHead != NULL);

}

 // 关闭全部套接字连接
void prvClientSockeDisconnectionALL( void )
{
	ClientSocketList_t *pNode = pClientSocketHead;	
	do
	{
		FreeRTOS_shutdown( pNode->xClientSocket, FREERTOS_SHUT_RDWR );
		FreeRTOS_closesocket( pNode->xClientSocket );
		pNode = pNode->pNextClientSocket;		
	}
	while(pNode != NULL);
}


 // TCP_Server测试任务
void Task_TCPTest(void *pvParameters)
{
	
	while(1)
	{
		prvSimpleServerRecive();
		if(recivebuffed.length > 0)
		{
			prvSimpleServerSend(recivebuffed.cRxBuffers,recivebuffed.length);
			recivebuffed.length = 0;
		}
		vTaskDelay(5 / portTICK_RATE_MS );
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值