skynet-游戏服务器心跳包的作用

->

心跳包的意义在哪里?

作用

首先查一下tcp的断线是否真的可靠

看到了一位同学的经验

点击跳转到原文

​ 之前的测试都是,手动强制关闭客户端进程,然后查看服务器的情况,结果往往是,服务器收到了客户端关闭的事件。其实,我一直忽略了一个问题,我没有拔掉网线来测试!

​ 上面的手动关闭客户端进程,事实上并不能测试出想要的结果,因为进程是在应用层的,所以,这种测试方法不能保证网络驱动层也不发送数据报文给服务器。经过测试发现,当应用层强制结束进程时,对于TCP连接,驱动层会发送reset数据包!而服务器收到这个数据包就可以正常关闭了!

​ 那么,如果拔掉网线呢,服务器收不到这个数据包,就会导致死连接存在!

​ 所以,心跳包是必要的,或者应用TCP协议本身的Keep-alive来设置

​ 之所以产生前面的误解,也是由于以前看书的时候,凭空想象,以为TCP连接如同一条绳子,一方断开了,另外一方必然会知道的。殊不知,TCP连接,这个“面向连接”的连接并不存在,它只是抽象出来的概念,对于物理层,对于网线、光纤而言,不存在连接不连接的概念,因为,对它们而言,无非就是一些电流脉冲而已。TCP的连接,不过是通过ACK、SEQ这些机制来模拟实现的。

以上为引用

这么看来socket本身的断开通知不是很靠谱,心跳包会更合理一些

那么心跳包的一个意义就是可以更可靠的检测连接是否畅通

之后询问了一下组内其他同学

他们表示,页游之前会用心跳包检测加速作弊

比如如果某玩家应用加速器作弊,那么他发送的心跳包时间时间间隔就会异常,这样就可以揪出作弊,但是。。作弊器已经越来越高端了,检测心跳包已经几乎没用,所以这个作用几乎没有了

心跳包曾经可以检测作弊

组内同学还表示,心跳包可以检测游戏延迟,不过。。。手游我检测个什么延迟

心跳包可以检测游戏延迟


skynet-mmo中心跳相关代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
local last_heartbeat_time
local HEARTBEAT_TIME_MAX = 3 * 100 -- 3秒钟未收到消息,则判断为客户端失联
local function heartbeat_check ()
if HEARTBEAT_TIME_MAX <= 0 or not user_fd then return end

local t = last_heartbeat_time + HEARTBEAT_TIME_MAX - skynet.now ()
if t <= 0 then
syslog.debugf ("--- heatbeat:%d, last:%d, now:%d", HEARTBEAT_TIME_MAX, last_heartbeat_timem, skynet.now() )

syslog.warning ("--- heatbeat check failed, exe kick_self()")
kick_self ()
else
skynet.timeout (t, heartbeat_check)
end
end

然后在每次收到客户端消息时,更新一下last time

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
local function handle_request (name, args, response)
local f = REQUEST[name]
if f then
syslog.debug ("^^^@ request from client, exe func:%s", name)
local ok, ret = xpcall (f, traceback, args)
if not ok then
syslog.warningf ("handle message(%s) failed : %s", name, ret)
kick_self ()
else
last_heartbeat_time = skynet.now () -- 每次收到客户端端请求,重新计时心跳时间
if response and ret then -- 如果该请求要求返回,则返回结果
send_msg (user_fd, response (ret))
end
end
else
syslog.warningf ("----- unhandled message : %s", name)
kick_self ()
end
end

a