前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Swoole中的长连接和心跳包

Swoole中的长连接和心跳包

作者头像
沈唁
发布2019-12-09 13:22:32
1.8K0
发布2019-12-09 13:22:32
举报
文章被收录于专栏:沈唁志沈唁志

长连接说简单一点就是不会断的连接 ? ,可以使用心跳包进行维持

心跳是什么?

顾名思义就是心脏的跳动,可以用来判断一个事物的生和死,Swoole 中的心跳是指用来判断一个连接是正常还是断开的

fd 是什么?

fd 学名是文件描述符(file descriptor),Swoole Server 中$fd 是 TCP 客户端连接的标识符,在 Server 实例中是唯一的,在多个进程内不会重复

fd 是一个自增数字,范围是 1 ~ 1600 万,fd 超过 1600 万后会自动从 1 开始进行复用

当连接关闭后 fd 会被新进入的连接复用,正在维持的 TCP 连接 fd 不会被复用

可以使用Server->getClientInfo函数来获取连接的信息,看一下我们可以通过 fd 获取到什么信息

代码语言:javascript
复制
var_dump($serv->getClientInfo($fd));

打印后的数据为:

代码语言:javascript
复制
array(10) {
  ["server_port"]=> // 服务端端口
  int(9501)
  ["server_fd"]=> // fd
  int(4)
  ["socket_fd"]=>
  int(11)
  ["socket_type"]=>
  int(1)
  ["remote_port"]=> // 客户端连接的端口
  int(49152)
  ["remote_ip"]=> // 客户端连接的 IP 地址
  string(9) "127.0.0.1"
  ["reactor_id"]=> // 来自哪个 Reactor 线程
  int(0)
  ["connect_time"]=> // 客户端连接到 Server 的时间,单位秒,由 master 进程设置
  int(1562741559)
  ["last_time"]=> // 最后一次收到数据的时间,单位秒,由 master 进程设置
  int(1562741559)
  ["close_errno"]=> // 连接关闭的错误码,如果连接异常关闭,close_errno 的值是非零
  int(0)
}

为什么要心跳?

当我们要关闭客户端连接时,我们可以在业务层对 fd 发起关闭连接的操作,以 Swoole 为例:

代码语言:javascript
复制
$serv->close($fd);

Swoole 会有 onClose 回调,之前我们也说了连接关闭后 fd 会被新进入的连接复用

正常情况下客户端中断 TCP 连接时,会发送一个 FIN 包,进行 4 次断开握手来通知服务器。但一些异常情况下,如客户端突然断电断网或者网络异常,服务器可能无法得知客户端已断开连接

尤其是移动网络,TCP 连接非常不稳定,所以需要一套机制来保证服务器和客户端之间连接的有效性,所以就有了心跳机制

什么是心跳机制?

心跳机制就是业务层来提供一个连接是否存活的一个方法,让系统能判定一个连接是否失效

一般有两种实现方式:

  1. 客户端定时发送一个心跳包,告诉服务器我还活着,服务器定时检测所有客户端列表,看他们最后一个心跳包的时间是否过长,如果过长,则认为已无心跳,判定为死连接,主动关闭这个连接
  2. 服务器定时询问所有的客户端,你们还活着么?如果活着,给我个回馈,没得到回馈的客户端,主动关闭这个连接
两种心跳方案有什么区别?

第一种方案,对服务器和网络的压力更小,而且更具有灵活性,但需要客户端配合定时发送心跳包

第二种方案,对服务器和网络压力更大,不建议使用

在 Swoole 中如何实现?

Swoole 扩展本身内置了这种机制,开发者只需要配置一个参数即可启用。Swoole 在每次收到客户端数据会记录一个时间戳,当客户端在一定时间内未向服务器端发送数据,那服务器会自动切断连接

使用方式

在 Server 启动时增加两个参数

代码语言:javascript
复制
$serv->set(array(
    'heartbeat_check_interval' => 5,
    'heartbeat_idle_time' => 10,
));

设置了这两个参数后,Swoole 底层将会创建心跳检测线程,通过定时轮询所有的连接,来判断连接的生死,所以 Swoole 的心跳不会堵塞任何业务逻辑

上面的设置就是每 5 秒侦测一次心跳,一个 TCP 连接如果在 10 秒内未向服务器端发送数据,将会被切断

配置建议

建议heartbeat_idle_timeheartbeat_check_interval的两倍多一点

这个两倍是为了进行容错,允许丢一个包,而多一点是考虑到网络的延时

你可以跟据实际的业务来调整这个容错率(允许丢几个包)

在客户端发送心跳包

使用定时器定时向服务端发送心跳

代码语言:javascript
复制
Swoole\Timer::tick(3000, function () use ($client) {
    $data = "heartbeat";
    $client->send($data);
});

服务端和客户端示例代码:https://github.com/sy-records/learn-swoole/tree/master/heartbeat

沈唁志,一个PHPer的成长之路! 任何个人或团体,未经允许禁止转载本文:《Swoole中的长连接和心跳包》,谢谢合作!

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-07-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 心跳是什么?
  • fd 是什么?
  • 为什么要心跳?
  • 什么是心跳机制?
    • 两种心跳方案有什么区别?
    • 在 Swoole 中如何实现?
      • 使用方式
        • 配置建议
          • 在客户端发送心跳包
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档