当前位置: 首页 > news >正文

tcp/ip异常断开调试笔记——lwip

问题一:异常掉线

异常断开模拟

1、单片机端做服务端(只监听一个客户端),电脑做客户端连接

2、尝试连接确定通信正常,断开网线。电脑客户端点击断开

3、经过一段时间(超过tcp/ip 3次握手时间)

4、接回网线后发现可以连接上但通信异常

原因分析

void StartDefaultTask(void *argument)
{/* init code for LWIP */MX_LWIP_Init();/* USER CODE BEGIN StartDefaultTask */struct sockaddr_in server_addr,client_addr;socklen_t sin_size;int recv_data_len;static uint8_t recv_data[RECV_DATA];again:sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0){LWIP_TCP_DEBUG("Socket error\n");close(sockfd);vTaskDelay(100);goto again;}//server_addr.sin_family = AF_INET;server_addr.sin_addr.s_addr = htonl(INADDR_ANY);server_addr.sin_port = htons(LOCAL_PORT);memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1){LWIP_TCP_DEBUG("Unable to bind\n");close(sockfd);vTaskDelay(100);goto again;}if (listen(sockfd, BACKLOG) == -1){LWIP_TCP_DEBUG("Listen error\n");close(sockfd);vTaskDelay(100);goto again;}/* Infinite loop */for(;;){sin_size = sizeof(struct sockaddr_in);connected = accept(sockfd, (struct sockaddr *)&client_addr, &sin_size);LWIP_TCP_DEBUG("new client connected from (%s, %d)\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));int tcp_nodelay = 1;//don't delay send to coalesce packetssetsockopt(connected,IPPROTO_TCP,TCP_NODELAY,(void *) &tcp_nodelay,sizeof(int));while(1){recv_data_len = recv(connected, recv_data, RECV_DATA, 0);if (recv_data_len <= 0){break;}//			write(connected,recv_data,recv_data_len);writeToRxBuf(recv_data, recv_data_len);}if (connected >= 0){close(connected);}connected = -1;//osDelay(1);}/* USER CODE END StartDefaultTask */
}

服务端未收到正常断开消息导致一直阻塞recv_data_len = recv(connected, recv_data, RECV_DATA, 0);

解决方案

TCP的keepalive机制

STM32 LWIP Server、Client如何判断网络异常_lwip检测网络状态-CSDN博客

void StartDefaultTask(void *argument)
{/* init code for LWIP */MX_LWIP_Init();/* USER CODE BEGIN StartDefaultTask */struct sockaddr_in server_addr,client_addr;socklen_t sin_size;int recv_data_len;static uint8_t recv_data[RECV_DATA];int so_keepalive_val = 1;    //使能心跳机制int tcp_keepalive_idle = 3;  //发�?�心跳空闲周�? 单位:秒int tcp_keepalive_intvl = 3; //发�?�心跳间�? 单位:秒int tcp_keepalive_cnt = 3;   //重发次数
//	int tcp_nodelay = 1;         //不延时发送到合并�?int err = 0;again:sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0){LWIP_TCP_DEBUG("Socket error\n");close(sockfd);vTaskDelay(100);goto again;}//使能心跳机制,默认没有使�?err = setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &so_keepalive_val, sizeof(int));if(err){}//server_addr.sin_family = AF_INET;server_addr.sin_addr.s_addr = htonl(INADDR_ANY);server_addr.sin_port = htons(LOCAL_PORT);memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1){LWIP_TCP_DEBUG("Unable to bind\n");close(sockfd);vTaskDelay(100);goto again;}if (listen(sockfd, BACKLOG) == -1){LWIP_TCP_DEBUG("Listen error\n");close(sockfd);vTaskDelay(100);goto again;}/* Infinite loop */for(;;){sin_size = sizeof(struct sockaddr_in);connected = accept(sockfd, (struct sockaddr *)&client_addr, &sin_size);//配置心跳�?测参数,默认参数时间很长。必须在accept之后,因为不是同�?个socket�?err = setsockopt(connected, IPPROTO_TCP, TCP_KEEPIDLE, &tcp_keepalive_idle, sizeof(int));err = setsockopt(connected, IPPROTO_TCP, TCP_KEEPINTVL, &tcp_keepalive_intvl, sizeof(int));err = setsockopt(connected, IPPROTO_TCP, TCP_KEEPCNT, &tcp_keepalive_cnt, sizeof(int));LWIP_TCP_DEBUG("new client connected from (%s, %d)\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));int tcp_nodelay = 1;//don't delay send to coalesce packetssetsockopt(connected,IPPROTO_TCP,TCP_NODELAY,(void *) &tcp_nodelay,sizeof(int));while(1){recv_data_len = recv(connected, recv_data, RECV_DATA, 0);//			recv_data_len = recv(connected, recv_data, RECV_DATA, MSG_DONTWAIT);//	        if (recv_data_len == -1)//	        {//	            if (errno == EAGAIN || errno == EWOULDBLOCK)//	            {//	            	osDelay(1);//	                continue;//	            }perror("read");exit(-1);//	            break;//	        }else if(recv_data_len > 0){//	        	writeToRxBuf(recv_data, recv_data_len);printf("recv client data : %s\n", recv_buf);//	        }else if(recv_data_len == 0){printf("client closed\n");//	            break;//	        }if (recv_data_len <= 0){break;}//						write(connected,recv_data,recv_data_len);writeToRxBuf(recv_data, recv_data_len);}if (connected >= 0){close(connected);}connected = -1;//osDelay(1);}/* USER CODE END StartDefaultTask */
}

问题二:卡死configASSERT( pxQueue->uxItemSize == 0 );

现象:客户端(电脑)显示还连着,可以发送数据,但是收不到数据。原因是已经先输入断言的死循环了。

如何调试以解决 configASSERT( pxQueue->uxItemSize == 0 );循环错误?- 合作伙伴和赞助商 / 恩智浦 - FreeRTOS 社区论坛


http://www.mrgr.cn/news/77812.html

相关文章:

  • Python 爬虫 (1)基础 | 基础操作
  • 力扣 LeetCode 513. 找树左下角的值(Day8:二叉树)
  • Java集合分页
  • mysql in查询大数据量业务无法避免情境下优化
  • tcp/ip异常断开调试笔记——lwip
  • 【Kubernetes系列】Kubernetes 中的探针模式
  • Oracle 19C 安装RAC磁盘投票失败
  • Vue实训---1-创建Vue3项目
  • 【大数据学习 | Spark-Core】Spark提交及运行流程
  • 【蓝桥杯C/C++】翻转游戏:多种实现与解法解析
  • 14.C++STL1(STL简介)
  • 【蓝桥杯C/C++】深入解析I/O高效性能优化:std::ios::sync_with_stdio(false)
  • minikube单机k8s出现Listen: listen tcp :53: bind: permission denied
  • 【题解】—— LeetCode一周小结46
  • CSRF保护--laravel进阶篇
  • 【大数据学习 | Spark-Core】spark-shell开发
  • 《线性代数的本质》
  • 【计算机网络】网段划分
  • C#语言入门
  • 《Shader 入门精要》学习笔记 茵蒂克丝
  • 用python将一个扫描pdf文件改成二值图片组成的pdf文件
  • [模版总结] - 树的基本算法4 -最近公共祖先 LCA
  • 【大数据学习 | Spark-Core】yarn-client与yarn-cluster的区别
  • 浦语提示词工程实践(LangGPT版,服务器上部署internlm2-chat-1_8b,踩坑很多才完成的详细教程,)
  • 复习!!!
  • Spring |(二)IoC相关内容 | bean