LWIP应用开发|心跳机制

心跳机制

1. 心跳机制简介

在长连接下,可能很长一段时间都没有数据往来。理论上说,这个连接是一直保持连接的,但是实际情况中,如果中间节点出现什么故障是难以知道的。更致命的是,有的节点(防火墙)会自动把一定时间之内没有数据交互的连接给断掉。这个时候,就可以使用心跳包,来维持长连接以及保活

心跳机制就是每隔几分钟发送一个固定信息给服务端,服务端收到后回复一个固定信息如果服务端几分钟内没有收到客户端信息则视客户端断开。发包方可以是客户也可以是服务端,具体看哪边实现更方便合理

心跳包的发送通常有以下两种技术

  • 应用层自已实现的心跳包:
    由应用程序自己发送心跳包来检测连接是否正常,服务器每隔一定时间向客户端发送一个短小的数据包,然后启动一个线程,在线程中不断检测客户端的回应, 如果在一定时间内没有收到客户端的回应,即认为客户端已经掉线;同样,如果客户端在一定时间内没有收到服务器的心跳包,则认为连接不可用
  • 使用SO_KEEPALIVE套接字选项:
    在TCP的机制里面,本身是存在有心跳包的机制的,也就是TCP的选项. 不论是服务端还是客户端,一方开启KeepAlive功能后,就会自动在规定时间内向对方发送心跳包, 而另一方在收到心跳包后就会自动回复,以告诉对方我仍然在线

下面将介绍如何使用SO_KEEPALIVE套接字选项来实现心跳检测

2. 心跳检测实现
2.1 setsockopt函数介绍

函数功能:设置与某个套接字关联的选项。选项可能存在于多层协议中,它们总会出现在最上面的套接字层。当操作套接字选项时,选项位于的层和选项的名称必须给出。为了操作套接字层的选项,应该将层的值指定为SOL_SOCKET。为了操作其它层的选项,控制选项的合适协议号必须给出。例如,为了表示一个选项由TCP协议解析,层应该设定为协议号TCP

函数原型:int setsockopt(int sock, 			//将要被设置选项的套接字
						int level, 			//选项所在的协议层
						int optname, 		//需要访问的选项名
						const void *optval, //指向包含新选项值得缓冲
						socklen_t optlen)	//现选项的长度
返 回 值:成功返回0;失败返回-1

参数(level)详细说明:level是指定控制套接字的层次,可以取如下三种值

  • SOL_SOCKET:通用套接字选项
选项名称(optname)   说明                   数据类型
========================================================================
SO_BROADCAST      允许发送广播数据         int
SO_DEBUG         允许调试            int
SO_DONTROUTE      不查找             int
SO_ERROR        获得套接字错误         int
SO_KEEPALIVE      保持连接            int
SO_LINGER        延迟关闭连接          struct linger
SO_OOBINLINE      带外数据放入正常数据流     int
SO_RCVBUF        接收缓冲区大小         int
SO_SNDBUF        发送缓冲区大小         int
SO_RCVLOWAT       接收缓冲区下限         int
SO_SNDLOWAT       发送缓冲区下限         int
SO_RCVTIMEO       接收超时            struct timeval
SO_SNDTIMEO       发送超时            struct timeval
SO_REUSERADDR      允许重用本地地址和端口     int
SO_TYPE         获得套接字类型         int
SO_BSDCOMPAT      与BSD系统兼容          int
========================================================================
  • IPPROTO_IP:IP选项
选项名称(optname)   说明                   数据类型
========================================================================
IP_HDRINCL       在数据包中包含IP首部      int
IP_OPTINOS       IP首部选项           int
IP_TOS         类型
IP_TTL         生存时间             int
========================================================================
  • IPPROTO_TCP:TCP选项
选项名称(optname)   说明                   数据类型
========================================================================
TCP_MAXSEG      TCP最大数据段的大小        int
TCP_NODELAY      不使用Nagle算法          int
========================================================================
2.2 心跳机制的实现

该实例实现的功能:在TCP客户端代码中加入心跳机制,使服务端在断网重连(与客户端)后,能自动保持连接

  • 参考Socket API编程优化一文,在该文的工程源码基础上进行修改
  • keepalive宏开关:将opt.h文件中的LWIP_TCP_KEEPALIVE宏定义开启
/**
 * LWIP_TCP_KEEPALIVE==1: Enable TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT
 * options processing. Note that TCP_KEEPIDLE and TCP_KEEPINTVL have to be set
 * in seconds. (does not require sockets.c, and will affect tcp.c)
 */
#if !defined LWIP_TCP_KEEPALIVE || defined __DOXYGEN__
#define LWIP_TCP_KEEPALIVE              1
#endif
  • setsockopt参数含义:sockets.h文件中可以看到如下setsockopt参数的设置
#define SO_KEEPALIVE   0x0008  /* 保持连接 */  					
#define TCP_KEEPIDLE   0x03    /* 发送心跳空闲周期 S*/			 
#define TCP_KEEPINTVL  0x04    /* 发送心跳间隔 S */			  
#define TCP_KEEPCNT    0x05    /* 心跳重发次数 */				 
  • 在工程中创建tcp_keepalive.c和对应的头文件
#include "socket_tcp_server.h"
#include "tcp_keepalive.h"
#include "socket_wrap.h"
#include "ctype.h"
#include "FreeRTOS.h"
#include "task.h"
static char ReadBuff[BUFF_SIZE];
void vTcpKeepaliveTask(void){
  int cfd, n, i, ret;
  struct sockaddr_in server_addr;
  int so_keepalive_val = 1;
  int tcp_keepalive_idle = 3;
  int tcp_keepalive_intvl = 3;
  int tcp_keepalive_cnt = 3;
  int tcp_nodelay = 1;
again:	
  //创建socket
  cfd = Socket(AF_INET, SOCK_STREAM, 0);
  //使能socket层的心跳检测
  setsockopt(cfd, SOL_SOCKET, SO_KEEPALIVE, &so_keepalive_val, sizeof(int));
	
  server_addr.sin_family = AF_INET;
  server_addr.sin_port = htons(SERVER_PORT);
  server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
  /*连接到服务器(connect是一个阻塞接口,内部要完成TCP的三次握手;
    里面有超时机制,所以需要等一段时间,才能重新连接到服务器)*/
  ret = Connect(cfd, (struct sockaddr*)&server_addr, sizeof(server_addr));
  if(ret < 0){
	//100ms去连接一次服务器
	vTaskDelay(100);
	goto again;
  }
  //配置心跳检测参数   默认参数时间很长
  setsockopt(cfd, IPPROTO_TCP, TCP_KEEPIDLE, &tcp_keepalive_idle, sizeof(int));	
  setsockopt(cfd, IPPROTO_TCP, TCP_KEEPINTVL, &tcp_keepalive_intvl, sizeof(int));	
  setsockopt(cfd, IPPROTO_TCP, TCP_KEEPCNT, &tcp_keepalive_cnt, sizeof(int));	
  setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY, &tcp_nodelay, sizeof(int));		
  printf("server is connect ok\r\n");

  while(1){
	//等待服务器发送数据
	n = Read(cfd, ReadBuff, BUFF_SIZE);
	if(n <= 0){	
	  goto again;	
	}
	//进行大小写转换
	for(i = 0; i < n; i++){	
      ReadBuff[i] = toupper(ReadBuff[i]);		
	}
	//写回服务器
	n = Write(cfd, ReadBuff, n);
	if(n <= 0){	
	  goto again;	
	}		
  }
}
  • 在freertos.c文件中的默认任务里面添加代码
void StartDefaultTask(void const * argument){
  /* init code for LWIP */
  MX_LWIP_Init();
  /* USER CODE BEGIN StartDefaultTask */
  printf("TCP keepalive test!\r\n");
  /* Infinite loop */
  for(;;){
    vTcpKeepaliveTask();
	osDelay(100);
  }
  /* USER CODE END StartDefaultTask */
}
2.3 心跳机制的测试比较

未加入心跳机制的代码测试

参考Socket API编程优化,将未加入心跳机制的TCP客户端代码下载到开发板中,开发板与电脑用网线连接好,设置到对应的IP地址信息(192.168.1.20)

  • 开启网络调试助手,打开一个服务端,监听192.168.1.20/端口6666;串口输出调试信息(server is connect ok);在服务器端输入小写字母,客户端会返回对应的大写字母

在这里插入图片描述
在这里插入图片描述

  • 将电脑和开发板之间的网线拔掉后重新连接,串口没有输出任何信息,仍显示server is connect ok;在服务器端发送信息,此时提示未建立通讯

在这里插入图片描述
在这里插入图片描述

加入心跳机制的代码测试

将2.2章节的心跳检测实例下载到开发板中,用网线连接电脑和开发板,确保串口通讯和服务器监听正常

  • 电脑和开发板之间的网线拔掉后,串口会输出错误信息“read socket error”,重新连接网线后,串口输出“server is connect ok”,表示已自动重新建立连接;网线重连后,在服务器端发送信息,能够正常回显对应的大写字母,表示服务端和客户端的通讯正常

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

  • 3
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论
### 回答1: 《lwip应用开发实战指南》是一本关于lwip协议栈应用开发的指南,以PDF形式提供。lwip是一个轻量级的开源TCP/IP协议栈,可以用于嵌入式系统和物联网设备的网络通信。 这本指南主要包含了lwip协议栈的原理介绍、应用示例和实战开发经验等内容。首先,指南会逐步介绍lwip协议栈的工作原理,包括数据包的封装和解封装、路由选择、连接管理等。读者可以通过这些基础知识了解lwip的工作流程和协议实现。 其次,指南还提供了一些lwip应用示例,例如建立基于lwip的服务器和客户端应用、使用lwip进行网络调试等。这些示例可以帮助读者更好地理解lwip的使用方法和技巧,并且提供了实际应用场景中的解决方案。 最后,指南还分享了一些实战开发经验和注意事项,帮助读者在开发lwip应用时避免常见的错误和问题。这些经验包括性能优化、内存管理、多线程处理等方面的技巧,可以帮助读者在实际开发中更好地利用lwip协议栈。 总体来说,这本《lwip应用开发实战指南》是一本对于想要学习和应用lwip协议栈的开发人员非常有用的资料。通过阅读这本指南,读者可以系统性地学习lwip的原理和使用方法,并且可以通过实际示例和经验分享来提升自己的开发水平。 ### 回答2: "lwip应用开发实战指南"是一本介绍lwIP(轻量级IP协议栈)应用开发的实战指南。该书针对lwIP提供了详细的开发指导和实例,有助于读者深入了解lwIP的原理和应用开发。 该指南首先介绍了lwIP的概念、特点和基本架构。随后,通过实际的案例演示,讲解了如何在不同的应用场景中使用lwIP进行网络通信。其中包括TCP/IP通信、UDP通信、网络调试等常见应用。 指南还详细介绍了lwIP的网络接口、协议栈和内存管理等关键要点。读者可以通过学习这些内容,深入掌握lwIP的核心技术,提升应用的性能和可靠性。 此外,该书还提供了一些实用的开发技巧和调试方法,帮助读者解决lwIP应用开发中常见的问题。通过这些实例和技巧,读者可以更好地理解lwIP的工作原理,掌握lwIP开发中的关键技术。 总之,《lwip应用开发实战指南》是一本对于lwIP应用开发者来说非常有价值的参考书。其以简明扼要的方式介绍了lwIP的原理和应用开发技巧,为读者提供了一个实际操作中的指导。无论是初学者还是有一定经验的开发者,都可以从中获得一些宝贵的经验和启示。希望读者能够通过本书的学习,掌握lwIP的开发技术,提高自己在网络应用开发中的水平。 ### 回答3: "LwIP应用开发实战指南"是一本针对LwIP(Lightweight IP)网络协议栈的应用开发实践指南的PDF电子书。LwIP是一种独立、可嵌入的开源网络协议栈,被广泛应用于嵌入式系统和物联网设备中。 这本指南通过实际案例和项目演示,详细介绍了如何使用LwIP协议栈进行应用开发。首先,它介绍了LwIP协议栈的基本概念和特性,包括TCP/IP协议、IP地址分配、套接字编程等内容。然后,它详细讲解了如何使用LwIP协议栈进行网络连接的建立和管理,包括网络接口的配置、DNS解析、TCP和UDP连接的建立等。同时,它还介绍了如何实现网络服务,例如HTTP服务器、FTP服务器等。 这本指南的特点之一是提供了大量的实例代码和可供实验的项目案例。读者可以通过按照书中的指导进行实验,逐步学习和掌握LwIP应用开发技巧。同时,这本指南还强调了实践和调试的重要性,通过解决实际问题的方式,帮助读者更好地理解和应用LwIP协议栈。 总的来说,“LwIP应用开发实战指南”是一本面向嵌入式系统和物联网设备开发人员的指导书,它通过实例和项目案例,帮助读者深入了解和应用LwIP协议栈进行网络应用开发。无论是初学者还是有一定经验的开发人员,都能从中获益,并提升他们的应用开发能力。
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

安迪西嵌入式

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值