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

ops/2024/11/22 23:41:05/

异常断开模拟

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 */
}


http://www.ppmy.cn/ops/135923.html

相关文章

电商系统架构演进

聊聊电商系统架构演进 具体以电子商务网站为例&#xff0c; 展示web应用的架构演变过程。 1.0时代 这个时候是一个web项目里包含了所有的模块&#xff0c;一个数据库里包含了所需要的所有表&#xff0c;这时候网站访问量增加时&#xff0c;首先遇到瓶颈的是应用服务器连接数&…

爬取链家二手房房价数据存入mongodb并进行分析

感谢您的关注&#xff01;需要完整源码评论区获取~ 【实验目的】 1. 使用 python 将爬虫数据存入 mongodb&#xff1b; 2. 使用 python 读取 mongodb 数据并进行可视化分析。 【实验原理】 MongoDB 是文档数据库&#xff0c;采用 BSON 的结构来存储数据。在文档中可嵌套其…

springboot中设计基于Redisson的分布式锁注解

如何使用AOP设计一个分布式锁注解&#xff1f; 1、在pom.xml中配置依赖 <dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.3.26</version></dependency><dependenc…

mysql的my.cnf配置文件参数说明

mysql的my.cnf配置文件参数说明 mysql的my.cnf配置文件参数说明&#xff0c;对于my.cnf的相关详细配置的参数说明和参数的常规配置 [mysqld] # ------------主要配置----------------- # 端口 port 3306# 数据地址 datadir/var/lib/mysql socket/var/lib/mysql/mysql.sock# …

【Python · PyTorch】卷积神经网络 CNN(LeNet-5网络)

【Python PyTorch】卷积神经网络 CNN&#xff08;LeNet-5网络&#xff09; 1. LeNet-5网络※ LeNet-5网络结构 2. 读取数据2.1 Torchvision读取数据2.2 MNIST & FashionMNIST 下载解包读取数据 2. Mnist※ 训练 LeNet5 预测分类 3. EMnist※ 训练 LeNet5 预测分类 4. Fash…

一文了解js 的正则

文章目录 正则基础正则应用正则性能优化特殊含义?.? 正则基础 一、正则表达式基础知识 什么是正则表达式&#xff1f; 正则表达式是一种用于匹配字符串中字符组合的模式。在JavaScript中&#xff0c;正则表达式是对象。它就像一个模板&#xff0c;可以帮助你在文本中查找、替…

Python设计模式详解之5 —— 原型模式

Prototype 设计模式是一种创建型设计模式&#xff0c;它通过复制已有的实例来创建新对象&#xff0c;而不是通过从头实例化。这种模式非常适合对象的创建成本较高或者需要避免复杂的构造过程时使用。Prototype 模式提供了一种通过克隆来快速创建对象的方式。 1. Prototype 模式…

java 可以跨平台的原因是什么?

我们对比一个东西就可以了&#xff0c;那就是chrome浏览器。 MacOS/Linux/Windows上的Chrome浏览器&#xff0c;那么对于HTML/CSS/JS的渲染效果都一样的。 我们就可以认为ChromeHTML/CSS/JS是跨平台的。 这里面&#xff0c;HTML/CSS/JS是不变的的&#xff0c;对于一个网页&a…