freertos_lwipstm32F2系列非线程安全需要加锁保护

freertos_lwipstm32F2系列⾮线程安全需要加锁保护
我在⼯作中需要在STM32F2系列下,⽤freertos和LWIP开发⼀个服务器端的TCP/IP服务。
由于内存有限并且freertos不便于利⽤fork函数新建线程,因此采⽤了select模式编写代码
开始通讯没有问题但是在多次连接或者长时间通讯时,会出现⽤于TCP/IP通讯的任务被挂起,导致⽆法再次接受数据,代码如下:
void NetZeroEntryFun(void const * argument)
{
int ts_sock_m = -1;
int ts_sock_s = -1;
int iSelectRet = -1;
struct sockaddr_in sin;
int sin_len = 0;
int i = 0;
int maxi = 0;
int maxfd;
fd_set rset;
fd_set allset;
int n_received = -1;
NET_MSG stNetMsg;
unsigned short usLen = 0;
static struct timeval timeout = {30, 0};
uint16_t nMode = 1;
//ether_init
Net_Initialize();
// allocate a socket
ts_sock_m = socket(AF_INET, SOCK_STREAM, 0);
if (ts_sock_m < 0)
{
return; // Couldn’t Allocate a TCP Socket
}
// Bind the socket to the local port number and IP address
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(net_astIp[0].port_no);
memcpy((int8_t *)&sin.sin_addr, (int8_t *)net_astIp[0].ip_server_address, 4);
// port number in network byte order
if (bind(ts_sock_m, (const struct sockaddr *)&sin, sizeof(sin)) < 0)    {
closesocket(ts_sock_m);
return; // Bind Failed
}
if (listen(ts_sock_m, NET_MAX_LINK) != 0) // 2 slave ports
{
closesocket(ts_sock_m);
return; // Listen Failed
}
/
/设置⾮阻塞模式
ioctlsocket(ts_sock_m,FIONBIO,&nMode);
FD_ZERO(&rset);
FD_ZERO(&allset);
FD_SET(ts_sock_m, &rset);
maxfd = ts_sock_m;
while (1)
2012奥运会羽毛球男双决赛{
FD_ZERO(&rset);
FD_SET(ts_sock_m, &rset);
for (i = 0; i < NET_MAX_LINK; i++)
{
if (net_astRecv0[i].ts_sock_s != -1)
{
FD_SET(net_astRecv0[i].ts_sock_s, &rset);
}
}
iSelectRet = select(maxfd + 1, &rset, NULL, NULL, &timeout);
if(iSelectRet < 0)
{/*错误*/
continue;
}
else if(iSelectRet == 0)
{/*超时*/
for (i = 0; i <= maxi; i++)
{
ts_sock_s = net_astRecv0[i].ts_sock_s;
if(ts_sock_s >= 0)
{/*⽂件描述符不⼤于0*/
closesocket(ts_sock_s);
FD_CLR(net_astRecv0[i].ts_sock_s, &rset);
net_astRecv0[i].ts_sock_s = -1;
1962饥荒net_astRecv0[i].ulTaskId = 0;
}
}
maxi = 0;
continue;
}
}
else
{
for (i = 0; i <= maxi; i++)
{
ts_sock_s = net_astRecv0[i].ts_sock_s;
if ((FD_ISSET(ts_sock_s, &rset)) && (ts_sock_s != -1))
{/*有链接则接收数据*/
n_received = recv(ts_sock_s, (int8_t *)stNetMsg.aucData,
sizeof(stNetMsg.aucData), MSG_DONTWAIT);
if (n_received <= 0)
{
closesocket(ts_sock_s);
FD_CLR(net_astRecv0[i].ts_sock_s, &rset);
net_astRecv0[i].ts_sock_s = -1;
net_astRecv0[i].ulTaskId = 0;
}
else
{
stNetMsg.usLength = n_received;
stNetMsg.ulTaskId = net_astRecv0[i].ulTaskId;
stNetMsg.ucRtNum = i;
stNetMsg.ucLtNum = NET_LISTEN_TASK0;
if ((stNetMsg.usLength > 7) &&
(stNetMsg.aucData[2] == 0x00) &&
(stNetMsg.aucData[3] == 0x00))
{
memcpy(&usLen, stNetMsg.aucData + 4, 2);
if (usLen == (unsigned short)(stNetMsg.usLength - 6))
{
xQueueSend(xCtrlQueueHandle, &stNetMsg, 0);
}
}
}
}
}
if (FD_ISSET(ts_sock_m, &rset))
{/*创建新的链接*/
sin_len = sizeof(struct sockaddr_in);
ts_sock_s = accept(ts_sock_m, (struct sockaddr *)&sin, (socklen_t *)&sin_len);
if (ts_sock_s == -1)
{
continue;
}
/*设置⾮阻塞模式*/
nMode = 1;
ioctlsocket(ts_sock_s,FIONBIO,&nMode);
for (i = 0; i < NET_MAX_LINK; i++)
{
{
if (net_astRecv0[i].ts_sock_s < 0)
{
net_astRecv0[i].ts_sock_s= ts_sock_s;
if (i > maxi)
maxi = i;
break;
}
}
if (ts_sock_s > maxfd)
maxfd = ts_sock_s;
}
}
osDelay(1);
}
}
开始担⼼⾃⼰select⽤法不对,因此特意做了⼀个最简单的没有select的TCP/IP通讯的服务端,但是还是与之前的效果⼀致。
开始对这个bug⾮常的困惑,也搜了不少关于LWIP和SELECT的⽤法都没有什么发现,后来⼀个同事(我的前辈哦)帮我搜索了⼀下,发现freertos_lwip是⾮线程安全的,也就是说我在调⽤recv和send的时候LWIP并没有做保护,⽽我调⽤的recv和send的还不在⼀个任务中,导致了recv和send相互堵塞的情况。
为了解决上述问题,在recv和send调⽤的时候添加了⼀个锁。在应⽤层保证了lwip的线程安全性,修改代码如下:红⾊部分。。。是修改的内容哦。。。。
修改后的接受部分:
while (1)
{
FD_ZERO(&rset);
FD_SET(ts_sock_m, &rset);
韩寒
for (i = 0; i < NET_MAX_LINK; i++)
{
if (net_astRecv0[i].ts_sock_s != -1)
{
FD_SET(net_astRecv0[i].ts_sock_s, &rset);泰妙菌素
}
}
iSelectRet = select(maxfd + 1, &rset, NULL, NULL, &timeout);
if(iSelectRet < 0)
{/*错误*/
continue;
}
else if(iSelectRet == 0)
{/*超时*/
for (i = 0; i <= maxi; i++)
{
ts_sock_s = net_astRecv0[i].ts_sock_s;
if(ts_sock_s >= 0)
{/*⽂件描述符不⼤于0*/
closesocket(ts_sock_s);
FD_CLR(net_astRecv0[i].ts_sock_s, &rset);
FD_CLR(net_astRecv0[i].ts_sock_s, &rset);
net_astRecv0[i].ts_sock_s = -1;
net_astRecv0[i].ulTaskId = 0;
}
}
maxi = 0;
continue;
}
else
{
for (i = 0; i <= maxi; i++)
{
ts_sock_s = net_astRecv0[i].ts_sock_s;
if ((FD_ISSET(ts_sock_s, &rset)) && (ts_sock_s != -1))
{/*有链接则接收数据*/
if(osOK == osSemaphoreWait(NET_SEMPHORE_ZEROHandle, MAX_DELAY))
{
n_received = recv(ts_sock_s, (int8_t *)stNetMsg.aucData, sizeof(stNetMsg.aucData), MSG_DONTWAIT);
osSemaphoreRelease(NET_SEMPHORE_ZEROHandle);
if (n_received <= 0)
{
closesocket(ts_sock_s);
钋-210
FD_CLR(net_astRecv0[i].ts_sock_s, &rset);
net_astRecv0[i].ts_sock_s = -1;
net_astRecv0[i].ulTaskId = 0;
}
else
{
stNetMsg.usLength = n_received;
stNetMsg.ulTaskId = net_astRecv0[i].ulTaskId;
stNetMsg.ucRtNum = i;
stNetMsg.ucLtNum = NET_LISTEN_TASK0;
if ((stNetMsg.usLength > 7) &&
(stNetMsg.aucData[2] == 0x00) &&
(stNetMsg.aucData[3] == 0x00))
{
memcpy(&usLen, stNetMsg.aucData + 4, 2);
if (usLen == (unsigned short)(stNetMsg.usLength - 6))
{
幸福是什么案例分析
xQueueSend(xCtrlQueueHandle, &stNetMsg, 0);
}
}
}
}
}
}
if (FD_ISSET(ts_sock_m, &rset))
{/*创建新的链接*/
sin_len = sizeof(struct sockaddr_in);

本文发布于:2024-09-22 12:54:30,感谢您对本站的认可!

本文链接:https://www.17tex.com/xueshu/349548.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:线程   没有   问题   代码   修改   链接   模式
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议