从零构建通讯器--7.1过往总结和心跳包代码实战

1.目录
在这里插入图片描述

一:前面学习的总结

核心架构浓缩总结实现的功能:

(1)服务器按照包头包体格式正确的接收客户端发送过来的数据包;
(2)根据手动的包的不同来执行不同的业务处理逻辑;
(3)把业务处理产生的结果数据包返回客户端;
(4)咱们用到的主要技术
-(a)epoll高并发通讯技术
-(b)线程池技术来处理业务逻辑
-(c)线程之间的同步技术包括互斥量、信号量
-其他技术:信号,日志打印,fork()子进程,守护进程
(5)借鉴了哪些官方nginx的精华代码
-(a)master进程,多个worker子进程——进程框架;
nginx:热更新,worker子进程挂了master能够重新启动worker;重载配置文件
【卷1讲解的主要是框架——包括通讯框架、包括业务逻辑处理框架,这才是我们本门课程的核心和精粹】
-(b)借鉴了epoll的一些实现代码;官方nginx用的ET【边缘触发模式】,咱们本项目中用的是水平触发模式LT
-(c)借鉴了接收数据包,以及发送数据包的核心代码;
官方nginx对我们项目的实现帮助不小,咱们借鉴的都是nginx中最核心,最值得借鉴的优秀代码;
(6)/哪些内容我们没有借鉴官方nginx呢?
//(a)比如epoll技术中我们采用LT模式来书写网络数据的接收和发送;
//(b)自己写一套线程池来处理业务逻辑,调用适当的业务逻辑处理函数,直至处理完毕把数据发送回客户端;
//(c)连接池 中 连接的 延迟 回收,以及专门处理数据发送的发送线程;

//目前为止:
//a)咱们服务器代码有没有什么瑕疵bug,导致比如说客户端发送恶意数据包能够把我们服务器攻击死呢?
//b)有没有代码能够进一步完善,写的更好; 提出问题,解决问题:

二、心跳包概念

1)规定消息代码0是心跳包
2)c/s程序:都有责任把心跳包机制在程序代码中实现好,以确保程序能良好的工作以及应付意外的情形发生;

在这里插入图片描述
2.1什么是心跳包?
1)心跳包其实就是 一个普通的数据包;
2)一般每个几十秒,最长一般也就是1分钟【10秒-60秒之间】,有客户端主动发送给服务器;服务器收到之后,一般会给客户端返回一个心跳包;
3)三路握手,tcp连接建立之后,才存在发送心跳包的问题—— 如果c(客户端)不给s发心跳包,服务器会怎样;
–》》服务器处理方法:约定 30秒发送 一次; 服务器可能会在90秒或者100秒内,主动关闭该客户端的socket连接;

你就应该主动关闭与服务器端的链接,并且如果业务需要重连,客户端程序在关闭这个连接后还要重新主动再次尝试连接服务器端;客户端程序 也有必要提示使用者 与服务器的连接已经断开;

2.2 为什么引入心跳包
1)常规客户端关闭,服务器端能感知到;但是有一种特殊情况,连接断开c/s都感知不到(c /s程序运行在不同的两个物理电脑上;tcp已经建立,这时拔掉c /s程序的网线; 拔掉网线导致服务器感知不到客户端断开-》》为了应对拔网线而引入心跳包);
法一:tcp本身keepalive机制;不重点研究,大家可以自己百度,因为检测时间不好控制,所以不适合我们;
法二:超时没有发送来心跳包,那么就会将对端的socket连接close掉,回收资源;这就是心跳包的作用;(心跳包其他作用:检测网络延迟等等;大家以后遇到再研究)

三:心跳包代码实战

(3.1)接收心跳包与返回结果
1)心跳包(ping包)-》规定消息代码为0;一般心跳包也不需要包体,只有包头就够了;
2)具体实现步骤

①ngx_c_slogic.h中添加成员函数说明
在这里插入图片描述
②ngx_c_slogic.cxx中添加函数0的处理函数
在这里插入图片描述
③处理函数
在这里插入图片描述
细节处理
在这里插入图片描述
把一个待发送消息入到消息队列中,发送消息
在这里插入图片描述

(3.2)处理不发送心跳包的客户端
1)3次机会:每次30秒;超过30*3 +10 =100秒,仍旧没收到心跳包,那么服务器端就把tcp断开;
2)增加配置Sock_WaitTimeEnable,Sock_MaxWaitTime
在这里插入图片描述
3)修改ReadConf()函数读取配置信息
在ngx_c_socket.cxx中的ReadConf()读配置
在这里插入图片描述
4)ngx_c_socket_time.cxx专门存放一些跟时间有关的函数;

①AddToTimerQueue() :把一个连接的信息加入到时间队列中来;该函数由 ngx_event_accept()函数在连接成功连入时调用;
AddToTimerQueue() 是定时器队列:官方nginx用红黑树做定时器,时间轮,;我们用multimap(红黑树做的容器,键-值队)来做定时器;
谁又来处理时间队列中的数据呢? 咱们的思路是 创建一个新线程,专门处理事件队列这个事;介绍新线程ServerTimerQueueMonitorThread();
a)创建线程(在Initialize_subproc初始化函数里面)
在这里插入图片描述
b)时间队列监视和处理线程,处理到期不发心跳包的用户踢出的线程
在这里插入图片描述

//
a)GetOverTimeTimer();根据给的当前时间,从m_timeQueuemap找到比这个时间更老(更早的)节点【1个】返回去,这些节点都是超时的
b)RemoveFirstTimer();把这个超时的节点从m_timeQueuemap删掉,并把这个节点的第二项返回来,**但是**因为下次超时时间还要判断,所以还要把这个节点加回来
c)procPingTimeOutChecking();这里需要检查心跳超时问题(虚函数,父类中啥也不干,在子类中做事)
d)zdClosesocketProc()  主动关闭一个连接要做的善后函数
e)改造inRecyConnectQueue();防止连接被多次扔进来

补充
f)ServerRecyConnectionThread();
在这里插入图片描述
h)clearAllFromTimerQueue()释放连接

3.3 测试代码编写

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值