STM32被拔网线 LWIP的TCP无法重连解决方案
目录
一、问题描述
二、项目构成
三、问题解决
1.问题代码
2.解决思路
3.核心代码:
四、完整代码
1.监测网口插入拔出任务
2.TCP任务
3.创建tcp任务
4.删除tcp任务
五、总结
一、问题描述
最近遇到一个问题,就是我的stm32设备作为tcp客户端和上位机交互,如果在连接过程中网线被拔断,等待时间稍微长一点再插上的话,tcp将不能再连接到服务器端,除非重启设备,所以我开始研究怎么解决这个lwip的小问题。
二、项目构成
MCU : STM32F429IGTx
网口芯片 :LAN8720
操作系统 :UCOSIII
协议栈:LWIP
调试工具:sscom5.13.1(可开启TCP服务端)
三、问题解决
1.问题代码
我们写了一个socket的tcp客户端作为一个单独的任务执行,recv这个函数阻塞,没数据的时候一直被阻塞,但是不影响其它任务,有了数据发过来,或者正常的tcp断开,recv函数就会收到数据往下执行,但是这时候我们遇到了一个问题,那就是TCP连接状态下,网线被拔出,recv这个函数没有做任何的反应,所以这便导致了recv这个函数一直被阻塞,插上网线以后不能重新像服务器进行tcp连接,理想状态下是recv函数应该也像正常tcp断开那样给我返回一个信号,那样我就知道tcp中断了,就去循环重新获取TCP连接,可是并没有,我们设备安装在现场难免会有网线被拔出的情况,一拔出再插入tcp就连接不上了说不过去,所以只能自己想办法解决这个问题。
2.解决思路
一开始的解决思路就是在tcp的recv下面加一个检测网线是否被插入的判断,如果网线被拔出的话,也break,跳出当前while去上一级while里面进行tcp连接,可是忽略了recv函数阻塞的问题,网线被拔出recv没有数据根本不往下执行,如果是netconn不阻塞的那种倒是可以,所以这个方案否了。
后来琢磨recv不是阻塞么,不如重新创建一个任务检测网口的网线插入状态,把这个tcp任务重新启动呢,最开始想到了挂起再恢复,后来发现恢复以后任务还会继续在阻塞里面,解决不了问题。想了想只能是拔出网线后删除tcp任务再重新创建了,为避免资源浪费,检测到网线拔出就删除tcp任务,检测到网线插入就创建tcp任务。
3.核心代码:
HAL库 LAN8720_ReadPHY(PHY_BSR) & PHY_LINKED_STATUS
标准库 ETH_ReadPHYRegister(LAN8720_PHY_ADDRESS, PHY_BSR) & PHY_Linked_Status)
如果网线是插入状态 代码的结果就是1
如果网线是拔出状态 代码的结果就是0
当tcp建立连接以后,就一直去判断网线有没有被拔出,如果被拔出了,就删除tcp任务。当tcp没有建立连接的时候,就一直去判断网线有没有被插入,插入的话就创建tcp任务,注意代码逻辑不要多次删除或者创建同一任务导致系统崩溃。
四、完整代码
1.监测网口插入拔出任务
u8 TCP_CONNECT_FLAG=0;//TCP连接状态 0是未连接 1是已连接 2是重新创建了任务待连接//1.监测网口插入拔出任务
void key_task(void *pdata)
{u8 res;OS_ERR err; while(1){/**key = KEY_Scan(0);if(key==KEY0_PRES) //发送数据{LED0 = !LED0;}**/if(TCP_CONNECT_FLAG==1){if(!(LAN8720_ReadPHY(PHY_BSR) & PHY_LINKED_STATUS)){//删除tcp任务TCP_CONNECT_FLAG=0;tcp_deletetask();}}else if(TCP_CONNECT_FLAG==0){if((LAN8720_ReadPHY(PHY_BSR) & PHY_LINKED_STATUS)){//打开tcp任务TCP_CONNECT_FLAG=2;tcp_starttask();}}OSTimeDlyHMSM(0,0,0,100,OS_OPT_TIME_HMSM_STRICT,&err); //延时2s}
}
2.TCP任务
#define PORT 5001
#define RECV_DATA (1024)
#define SERV_IP_ADDR "192.168.0.222"
#define SERV_PORT 8088
unsigned char rec_buffers[1024]={"0X66,0x14,0x97,0x0F,0x1D,0xEA\n"};
unsigned char rec_buffers2[1024]={"\n"};
extern u8 TCP_CONNECT_FLAG;
int sock=-1;void tcp_thread(void *arg)
{OS_ERR err;int block = 1;struct sockaddr_in Serv_addr;//char*recv_data;int recv_data_len;/*为recv_data申请内存空间 申请成功返回内存空间首地址 失败返回NULL*///recv_data=(char*)malloc(RECV_DATA);//if(recv_data==NULL){//printf("Mallo memory failed\r\n");// }while(1){if(sock!=-1){closesocket(sock);sock=-1;}/* 为sockaddr_in结构体成员赋值,用于以下的connect绑定 参数protocol在TCP/TCP两种协议下均为0 *//*套接字申请成功返回Socket描述符(int类型) 失败返回-1*/sock=socket(AF_INET,SOCK_STREAM,0);if(sock<0){// printf("Socket error\n");OSTimeDlyHMSM(0,0,0,10,OS_OPT_TIME_HMSM_STRICT,&err);continue;}//ioctlsocket(sock,FIONBIO,&block); /*TCP/IP – IPv4*/Serv_addr.sin_family=AF_INET;/*绑定远端服务器的端口*/Serv_addr.sin_port=htons(SERV_PORT);/*绑定远端服务器的ip*/Serv_addr.sin_addr.s_addr=inet_addr(SERV_IP_ADDR);/* 清空sockaddr_in结构体内存空间 sin_zero是为了让sockaddr与sockaddr_in两个数据结构保持大小相同而保留的空字节 */memset(&(Serv_addr.sin_zero), 0, sizeof(Serv_addr.sin_zero)); /* 连接远端服务器 */if (connect(sock, (struct sockaddr *)&Serv_addr, sizeof(struct sockaddr)) == -1) {//printf("Connect failed!\n");closesocket(sock);OSTimeDlyHMSM(0,0,0,10,OS_OPT_TIME_HMSM_STRICT,&err);continue;}TCP_CONNECT_FLAG=1;//printf("Connect to tcp server successful!\n"); while(1){ /* 成功接收到数据,返回接收的数据长度 */recv_data_len = recv(sock, rec_buffers2, RECV_DATA, 0);if (recv_data_len <= 0){ break; }else{write(sock,rec_buffers,1024);}/* 串口打印接收的数据内容 *///printf("recv:%s\n",recv_data);/* 发送数据内容 */OSTimeDlyHMSM(0,0,0,5,OS_OPT_TIME_HMSM_STRICT,&err); }OSTimeDlyHMSM(0,0,0,5,OS_OPT_TIME_HMSM_STRICT,&err);}}
3.创建tcp任务
void tcp_starttask(){OS_ERR err;CPU_SR_ALLOC();OS_CRITICAL_ENTER();//进入临界区OSTaskCreate((OS_TCB * )&TcpTaskTCB, (CPU_CHAR * )"tcp task", (OS_TASK_PTR )tcp_thread, (void * )0, (OS_PRIO )TCP_PRIO, (CPU_STK * )&TCP_TASK_STK[0], (CPU_STK_SIZE)TCP_STK_SIZE/10, (CPU_STK_SIZE)TCP_STK_SIZE, (OS_MSG_QTY )0, (OS_TICK )0, (void * )0, (OS_OPT )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,(OS_ERR * )&err);OS_CRITICAL_EXIT(); //退出临界区
}
4.删除tcp任务
void tcp_deletetask(){OS_ERR err;CPU_SR_ALLOC();OS_CRITICAL_ENTER();//进入临界区OSTaskDel((OS_TCB * )&TcpTaskTCB,&err);OS_CRITICAL_EXIT(); //退出临界区}
五、总结
算是解决了网线拔出再插入以后tcp不能重新建立连接的问题,可能方法过于简单粗暴,如果大佬有更好的方法解决这个问题欢迎交流指导。
相关文章:

STM32被拔网线 LWIP的TCP无法重连解决方案
目录 一、问题描述 二、项目构成 三、问题解决 1.问题代码 2.解决思路 3.核心代码: 四、完整代码 1.监测网口插入拔出任务 2.TCP任务 3.创建tcp任务 4.删除tcp任务 五、总结 一、问题描述 最近遇到一个问题,就是我的stm32设备作为tcp客户端…...

Linux下开放指定端口
比如需要开放82端口: #查询是否开通 firewall-cmd --query-port82/tcp#开放端口82 firewall-cmd --zonepublic --add-port82/tcp --permanent#重新加载防火墙 firewall-cmd --reload...

亚马逊测评行为的识别与防范:教你如何搭建安全的测评环境
亚马逊平台以其严格的内部系统和精密的买家信息对比机制而闻名。一旦发现买家存在不当评价行为,系统会立即展开深入的调查,追溯其所有的购买和评价记录。如果确认该买家存在补评价的行为,那么他/她之前留下的所有评价都可能会被系统自动删除。…...

如何通过成熟的外发平台,实现文档安全外发管理?
文档安全外发管理是企业信息安全管理的重要组成部分,它涉及到企业向外发送的文件,需要进行严格的控制和管理,防止敏感或机密信息的泄露。以下是一些关键考虑因素: 文件外发的挑战:企业在文件外发时面临的主要挑战包括…...

SCI一区级 | Matlab实现SSA-CNN-GRU-Multihead-Attention多变量时间序列预测
目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.【SCI一区级】Matlab实现SSA-CNN-GRU-Multihead-Attention麻雀算法优化卷积门控循环单元融合多头注意力机制多变量时间序列预测,要求Matlab2023版以上; 2.输入多个特征,输出单个…...

Mysql中的几种常见日志
引言 本文是对Mysql中几种常见日志及其作用的介绍 一、error log(错误日志) MySQL 中的 error log(错误日志)是一种非常重要的日志类型,它记录了 MySQL 服务器在启动、运行及关闭过程中遇到的所有重要事件、错误信…...

2024年7月22日(nfs samba)
一、webserver 服务器:作用是发布nginx的web项目 1、安装nginx(只下载不安装) [rootweb_server ~]# yum -y install --downloadonly --downloaddir./soft/ nginx 2、配置一个本地的nginx仓库 [rootweb_server ~]# yum -y install createrepo…...
黑龙江网络安全等级保护测评策略概述
一、简介 黑龙江省网络安全等级保护测评策略是为了保障信息系统安全稳定运行,根据《网络安全法》和相关国家标准制定的综合性安全评估和加固过程。该策略不仅要求企业和机构明确自身信息系统的安全等级,还指导其实施相应的技术防护与管理措施࿰…...

笔记 7 :linux 011 注释,函 bread () , get_hash_table () , find_buffer ()
(57)接着介绍另一个读盘块的函数 bread,以及释放 bh 的函数 brelse( ): (58)因为 函数 get_blk()大量调用了其它函数,一版面列举不完,…...

vscode配置latex环境制作【文档、简历、resume】
vscode配置latex环境制作【文档、简历、resume】 1. 安装Tex Live及vscode插件 可以参考:vscode配置latex环境制作beamer ppt 2. 添加vscode配置文件 打开vscode,按下Ctrl Shift P打开搜索框,搜索Preference: Open User Settings (JSON…...

如何学习Spark:糙快猛的大数据之旅
作为一名大数据开发者,我深知学习Spark的重要性。今天,我想和大家分享一下我的Spark学习心得,希望能够帮助到正在学习或准备学习Spark的朋友们。 目录 Spark是什么?学习Spark的"糙快猛"之道1. 不要追求完美,在实践中学习2. 利用大模型作为24小时助教3. 根据自己的节…...
交换机(Switches)和桥(Bridges)的区别
交换机(Switches)和桥接器(Bridges)在网络和通信领域中都起着重要作用,它们有一些共同点,但也有一些显著的区别: 工作层次: 桥接器(Bridges):桥接…...

基于springboot+vue的汽车租赁管理系统
摘要 在当今快速发展的数字化时代,汽车租赁行业作为现代服务业的重要组成部分,正面临着前所未有的机遇与挑战。为提升管理效率、优化用户体验并促进业务增长,我们设计并实现了一套基于Spring Boot后端框架与Vue.js前端技术的汽车租赁管理系统…...

《0基础》学习Python——第二十二讲__网络爬虫/<5>爬取豆瓣电影封面图
一、爬取豆瓣电影的图片封面 1、经过上节课我们所爬取的豆瓣电影的电影名、年份、国家、导演、主演、剧情,那么接下来我们将学习如何去爬取这些电影的图片,并将这些图片存放在文件夹中。 2、过程实现: 2.1、获取网页源码 首先还是和爬取电影名…...

全新UI自助图文打印系统小程序源码/自助云打印机前后端源码
全新UI自助图文打印系统小程序源码,自助云打印机前后端源码。最新的自助图文打印系统和证件照云打印小程序源码采用了PHP作为后端开发语言,旨在为用户提供全面的自助打印服务。 这些服务覆盖了多种文件格式,包括文档、图片、表格等。除此之外…...

yolo5图片视频、摄像头推理demo
yolo5图片、视频推理demo 图片 import torch# 加载预训练模型 model torch.hub.load(./yolo5, custom, pathyolov5s.pt, sourcelocal)# 加载图片 img 1.jpg# 进行推理 results model(img)# 解析结果 detections results.xyxy[0].cpu().numpy() # [x1, y1, x2, y2, confid…...
Scala学习笔记19: 隐式转换和隐式参数
目录 第十九章 隐式转换和隐式参数1- 隐式转换1. 隐式准换函数: 施展魔法的咒语2. 隐式类: 为已有类型添加魔法3. 隐式转换规则: 魔法生效的条件4. 举例说明: 见证魔法的时刻5. 注意事项: 谨慎使用魔法 2. 隐式参数1. 语义: 隐藏在背后的参数2. 使用 隐式参数的方式2.1 隐式值:…...

用户登录安全是如何保证的?如何保证用户账号、密码安全?
1.HTTP协议直接传输密码(无加密) 前端 直接发送HTTP请求(无加密),攻击者可直接捕获网络包,看到下面的明文信息 因此,使用HTTP协议传输会直接暴露用户敏感信息。 2.HTTPS协议直接传输密码&…...

Java 写一个可以持续发送消息的socket服务端
前言 最近在学习flink, 为了模仿一个持续的无界的数据源, 所以需要一个可以持续发送消息的socket服务端. 先上效果图 效果图 socket服务端可以持续的发送消息, flink端是一个统计单词出现总数的消费端,效果图如下 源代码 flink的消费端就不展示了, 需要引入一些依赖和版本…...
Ubuntu2204搭建ceph17
Ceph 环境初始化搭建Ceph 本次实验基于VMware17 节点IPstorage01192.168.200.161storage01192.168.200.162storage01192.168.200.163 环境初始化 初始化基础环境,三节点执行 #!/bin/bash# 定义节点信息 NODES("192.168.200.161 storage01 root" "…...

【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...
深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法
深入浅出:JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中,随机数的生成看似简单,却隐藏着许多玄机。无论是生成密码、加密密钥,还是创建安全令牌,随机数的质量直接关系到系统的安全性。Jav…...

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...

ServerTrust 并非唯一
NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...
【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)
1.获取 authorizationCode: 2.利用 authorizationCode 获取 accessToken:文档中心 3.获取手机:文档中心 4.获取昵称头像:文档中心 首先创建 request 若要获取手机号,scope必填 phone,permissions 必填 …...
重启Eureka集群中的节点,对已经注册的服务有什么影响
先看答案,如果正确地操作,重启Eureka集群中的节点,对已经注册的服务影响非常小,甚至可以做到无感知。 但如果操作不当,可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...
#Uniapp篇:chrome调试unapp适配
chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器:Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...

手机平板能效生态设计指令EU 2023/1670标准解读
手机平板能效生态设计指令EU 2023/1670标准解读 以下是针对欧盟《手机和平板电脑生态设计法规》(EU) 2023/1670 的核心解读,综合法规核心要求、最新修正及企业合规要点: 一、法规背景与目标 生效与强制时间 发布于2023年8月31日(OJ公报&…...

【C++】纯虚函数类外可以写实现吗?
1. 答案 先说答案,可以。 2.代码测试 .h头文件 #include <iostream> #include <string>// 抽象基类 class AbstractBase { public:AbstractBase() default;virtual ~AbstractBase() default; // 默认析构函数public:virtual int PureVirtualFunct…...

VisualXML全新升级 | 新增数据库编辑功能
VisualXML是一个功能强大的网络总线设计工具,专注于简化汽车电子系统中复杂的网络数据设计操作。它支持多种主流总线网络格式的数据编辑(如DBC、LDF、ARXML、HEX等),并能够基于Excel表格的方式生成和转换多种数据库文件。由此&…...