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

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 packets
		setsockopt(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 packets
		setsockopt(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 );


http://www.kler.cn/a/406107.html

相关文章:

  • 【代码随想录day38】【C++复健】322. 零钱兑换;279.完全平方数;139.单词拆分;卡码网56. 携带矿石资源
  • 高中-信息技术科目考试-编程题
  • 【Unity How】Unity中如何实现物体的匀速往返移动
  • python oa服务器巡检报告脚本的重构和修改(适应数盾OTP)有空再去改
  • python常用的排序算法
  • IDEA2019搭建Springboot项目基于java1.8 解决Spring Initializr无法创建jdk1.8项目 注释乱码
  • Android音频采集
  • C# NetworkStream用法
  • 我对软考“背背背”的看法
  • [已解决]Tomcat 9.0.97控制台乱码
  • Pytorch 遇到 NNPACK 初始化问题unsupported hardware
  • CSS给元素的四个角添加边框
  • 《Django 5 By Example》阅读笔记:p651-p678
  • Python学习32天
  • LeetCode 101题集(随时更新)
  • 【Python】【持续项目】Python-安全项目搜集
  • AI、VR与空间计算:教育和文旅领域的数字转型力量
  • 《数字图像处理基础》学习06-图像几何变换之最邻近插值法缩小图像
  • C语言:strcpy
  • OpenCV和Qt坐标系不一致问题
  • window 中安装 php 环境
  • 云高性能计算 CHPC :基因研究的加速器(二)使用Docker工作流示例
  • PID多变量解耦控制
  • Spring Boot3.x自动配置不生效的排查与解决:IDEA 文件夹命名导致的问题
  • 大数据学习17之Spark-Core
  • wordpress二开-WordPress新增页面模板-说说微语