文档章节

swoole应答式消息发送重试功能实现

吾爱
 吾爱
发布于 01/28 16:15
字数 690
阅读 92
收藏 0

用swoole做了个长连接TCP服务器,server和多台client之间交互是发送/应答的形式,这里面需要做一个消息重试机制,比如:

Server 发送一条消息 message_1 给 ClientA ,约定5秒重发一次,最多尝试3次,期间server如果收到 message_2 则自动取消重试。

首先想到的是,在发送message_1后,启动一个 swoole_timer_tick 定时器,设定间隔时间为5秒,同时将$timerId 保存到全局变量 array $timers 中例如:

//... 假设 $msg1 是一个封装的Msg对象,包含消息标识,数据等信息
$server->send($fd, $msg1->data);
//创建一个定时器
$timerID = \swoole_timer_tick(5000, function() use ($server,$fd,$msg1) {
    $server->send($fd,$msg1->data);
});
//保存$timerID, key是由fd和消息标识组成,保证每个连接每条消息的定时器不重复
$key = $fd.'_'.$msg1->id; //假设 id=1
$timers[$key] = $timerID;

当接收到消息的时候,清除定时器

$server->on('receive',function($server,$fd){
    global $timers;
     //解析消息过程略
    $key = $fd.'_1';
    if (isset($timers[$key])) {
        $server->clearTimer($key);
        unset($timers[$key]);
    }    
});

看起来没啥问题,但是首先需要知道一个重要的点:

定时器是进程隔离的!在一个woker进程中创建的定时器,哪怕把timerID存放到redis或者其他共享内存中,也无法在其他进程中通过timerID清除,在哪个进程中创建的定时器就必须在哪个进程中销毁。

不过幸运的是,如果你没有特别配置,swoole默认一个fd固定在一个woker上的,这里的代码并不会有什么问题。

但是如果在其他worker中主动向fd发送了一条消息,比如在运维端口下面 (多端口监听)向指定的client发送指定的消息,这时候由于执行发送程序是在运维的TCP链路上,并不一定和fd在同一个worker中,如果此时启动了定时器,但是接收消息的时候是在fd的worker中,clearTimer就会报错,定时器不存在,因为定时器是在运维worker中创建的。

这个问题困扰了我一天,甚至想过换语言,用go重写整个服务,去TMD恶心的进程间通信,最终还是找到了解决方法,用的是 pipeMessage。

大致步骤如下:

$server对象中有一个 woker_id 属性,当client连上来的时候可以把 fd,worker_id保存到 swoole_table或redis中。

然后发送消息封装一下,发送之前先判断一下当前worker_id和指定fd的worker_id是否一致,不一致则通过 $server->sendMessage() 发送给fd绑定的worker处理。

算是解决了这个问题吧。。。

© 著作权归作者所有

共有 人打赏支持
吾爱
粉丝 143
博文 264
码字总数 89585
作品 0
后端工程师
Apache ActiveMQ实战(1)-基本安装配置与消息类型

ActiveMQ简介 ActiveMQ是一种开源的,实现了JMS1.1规范的,面向消息(MOM)的中间件,为应用程序提供高效的、可扩展的、稳定的和安全的企业级消息通信。ActiveMQ使用Apache提供的授权,任何人都...

lifetragedy
2016/07/06
0
0
swoole实现Timer定时器、心跳检测及Task进阶实例:mysql连接池

Table of Contents 1.Timer定时器 2.心跳检测 3.Task进阶:MySQL连接池 环境说明: 系统:Ubuntu14.04 (安装教程包括CentOS6.5) PHP版本:PHP-5.5.10 swoole版本:1.7.7-stable 1.Timer定时...

太阳黑子
2016/10/28
127
0
基于SWOOLE的分布式SOCKET消息服务器架构

消息服务器使用socket,为避免服务器过载,单台只允许500个socket连接,当一台不够的时候,扩充消息服务器是必然,问题来了,如何让链接在不同消息服务器上的用户可以实现消息发送呢? 要实现...

tomener
2016/06/16
339
0
PHP的异步并行扩展Swoole发布1.7版本

Swoole 1.7.0 发布了,该版本主要改进内容包括: reactor线程与writer线程合并 对send优化,加入out_buffer机制 增加AIO异步读写文件的API 增加DNS异步查询函数 swooleclient在php-fpm或apa...

matyhtf
2014/04/17
6K
39
swoole-1.8.0 发布,PHP 的异步并行 C 扩展

Swoole-1.8.0 版本已发布,此版本是一个里程碑式新版本,新增了多项新特性、多项核心功能优化以及问题修复、移除了无效的特性。更新内容如下: 客户端 增加原生异步 MySQL 客户端 增加原生异...

matyhtf
2016/01/27
3K
24

没有更多内容

加载失败,请刷新页面

加载更多

下一页

java并发备忘

不安全的“先检查后执行”,代码形式如下: if(条件满足){ //这里容易出现线程安全问题//doSomething}else{//doOther} 读取-修改-写入 原子操作:使用CAS技术,即首先从V中读取...

Funcy1122
今天
0
0
SpringBoot2.0 停机

最近新建了个SpringBoot2.0的项目,因为原来一直使用的是传统的Tomcat部署war包的形式,所以这次SpringBoot内置Tomcat部署jar包的时候遇到了很多问题。其中一个就是因为没有外置的Tomcat容器...

Canaan_
昨天
0
1
Confluence 6 外部参考

一个外部参考的意思是任何站点链接到你 Confluence 的实例。任何时候当 Confluence 的用户单击这个外部链接的时候,Confluence 可以记录这次单击为参考。 在默认的情况下,外部链接的参考链接...

honeymose
昨天
0
0
Android中的设计模式之抽象工厂模式

参考 《设计模式解析》 第十一章 Abstract Factory模式 《设计模式:可复用面向对象软件的基础 》3.1 Abstract Factory 抽象工厂 对象创建型模式 《Android源码设计模式解析与实战》第6章 创...

newtrek
昨天
0
0
Redis | 地理空间(GEO)的一个坑

Redis的地理空间(Geo)是个好东西,轻轻松松的就可以把地图描点的问题处理了, 最近却遇到一个坑...Redis采用的Msater-Slave模式, 运用GEORADIUS在salve读取对应的数据,新增了从节点但是从不返...

云迹
昨天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部