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: //创建socketcfd = 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”,表示已自动重新建立连接;网线重连后,在服务器端发送信息,能够正常回显对应的大写字母,表示服务端和客户端的通讯正常
LWIP应用开发|心跳机制相关推荐
- LWIP网络开发从入门到精通
LWIP网络开发从入门到精通 1. LWIP应用开发 | LWIP协议栈 2. LWIP应用开发 | 以太网基础知识 3. LWIP应用开发 | TCP/IP协议簇一 4. LWIP应用开发 | TC ...
- 开发im即时通讯如何用Netty实现心跳机制、断线重连机制
所谓心跳, 即在 TCP 长连接中, 客户端和服务器之间定期发送的一种特殊的数据包, 通知对方自己还在线, 以确保 TCP 连接的有效性. 注:心跳包还有另一个作用,经常被忽略,即:一个连接如果长时间 ...
- [心跳] 使用心跳机制实现CS架构下多客户端的在线状态实时更新以及掉线自动重连...
此文讲述的内容是一个实际项目开发中的一部分内容,笔者将亲身经历写成文章. [背景] 现 需要实现这样的功能:有多个客户端连着同一个服务器.服务器和客户端之间需要"互相"知道彼此的连 ...
- 基于Windows Socket 的网络通信中的心跳机制原理
引言 在采用TCP 连接的C/S 结构的系统中,当通信的一方正常关闭或退出时,另一方能收到相应的连接 断开的通知,然后进行必要的处理:但如果任意一方发生所谓的"非优雅断开",如:意 ...
- php 如何实现心跳包,Socket心跳机制-JS+PHP实现
本文是我在实际工作中用到的Socket通信,关于心跳机制的维护方式,特意总结了一下,希望对朋友们有所帮助. Socket应用:首先Socket 封装了tcp协议的,通过长连接的方式来与服务器通信,是由 ...
- Android心跳包(一)——心跳机制
转自:http://blog.csdn.net/rabbit_in_android/article/details/50119809 在写之前,我们首先了解一下为什么android维护长连接需要心跳机 ...
- TCP长连接与短连接、心跳机制
转自: 1. TCP连接 当网络通信时采用TCP协议时,在真正的读写操作之前,server与client之间必须建立一个连接,当读写操作完成后,双方不再需要这个连接时它们可以释放这个连接,连接的建立是 ...
- 高性能高可用MySQL(主从同步,读写分离,分库分表,去中心化,虚拟IP,心跳机制)
高性能高可用MySQL(主从同步,读写分离,分库分表,去中心化,虚拟IP,心跳机制) 视频地址:https://www.bilibili.com/video/BV1ry4y1v7Tr?p=8& ...
- java udp心跳机制_心跳包机制整理汇总
[背景] 现需要实现这样的功能:有多个客户端连着同一个服务器.服务器和客户端之间需要"互相"知道彼此的连接状态.比如在某一时刻,服务器需要知道当前有多少个客户端正在和其通信:某一个 ...
最新文章
- c#属性的相关学习总结。
- php mb strimwidth,wordpress截断函数mb_strimwidth()失效的解决方法
- ELK之ElasticSearch快速入门
- 在 Go 语言中 Patch 非导出函数
- Java技术:serialVersionUID作用介绍
- Blazor正式成为Microsoft官方.NET 和WebAssembly项目
- 读书笔记:Information Architecture for the World Wide Web, 3rd Edition 北极熊 第一部分 1-3...
- Effective Java~3. 私有Constructor 或Enum 强化单例
- 实时化或成必然趋势?新一代 Serverless 实时计算引擎
- Docker(4)-容器互联与端口映射
- 环形buffer缓冲区
- java随机姓名_Java随机产生中文昵称
- 使用cacti监控CISCO交换机
- TCP通讯知识点总结
- 分数阶灰色模型的python实现
- HP ProOne G2 20-in 一体机开后盖换电池记事
- 老子智慧 之 知人者智 自知者明 [明智]
- 「SQL面试题库」 No_55 销售分析 I
- JAVA版B2B2C商城源码 拼团商城 分销商城 springboot商城多商家入驻商城系统
- 好习惯是成功的关键(最经典的成功思维)
热门文章
- java入门(3)——简易绘图板
- Avoid object allocations during draw/layout operations
- 作文提升~老师整理的优美比喻句太实用
- layui表格自定义分页
- 石英晶振常用术语解释
- 人生重开模拟器(Python实现)
- 苹果频率测试软件gen,【技术干货】进行精准的PCIe 4.0时钟抖动测量
- YZ-9846时间同步装置 “四统一、四规范”,确保各时间同步设备时间高精度统一
- 燃爆2022年的微服务架构
- pjmedia系列之媒体设备pjmedia_snd_port