使用php+swoole对client数据实时更新(二) (转)

上一篇提到了swoole的基本使用,现在通过几行基本的语句来实现比较复杂的逻辑操作:

先说一下业务场景。我们目前的大多数应用都是以服务端+接口+客户端的方式去协调工作的,这样的好处在于不论是处在何种终端的情况下,都可以完美的和服务端兼容。这样就轻松实现了MVC各个部分的真正解耦。但是提高程序的友好性还是有很多路要走,其中一个大家都会遇到的就是数据实时更新的问题。比如一个用户在手机上做了添加操作,这时候其他的终端也应该及时显示数据的变化情况。这个对于手机来说还算好办,因为现在的各种推送服务完全可以满足需求,当收到推送更新时,根据推送内容请求相应接口就可以了。但是放到PC上就不是这么回事了。浏览器和http协议的特殊性质不得不让我们另辟蹊径。

举一个大家生活中都会遇到的场景:
某个周末你想要和女朋友去看一场电影,你在自己的pc上找到了某场的场次和座位。正当你要下单支付时,系统提示该座位已经售出,这时你不得不重新回到选座页面重新挑选。那如果改进一下产品体验,当有别的用户已经购买某个座位的时候,浏览器会及时将座位标识已售出,这样你就不用来回操作,节省操作时间。

** 针对上述的情景呢,这里有一个系统间交互的流程图:**

  • 上面一行就是使用系统的当前用户,他对数据进行了相关操作,同时返回操作结果

下面一行是其他用户也正在操作同一条数据。当①(绿色)返回结果时,web服务器会同时告诉当前用户和redis队列服务(①黄色),因为websocket服务实时监听redis,这样一旦有数据变化,websocket服务会及时感知。此时通过与浏览器建立的长连接进行通讯并告知数据已经更新并重新加载。

另外一种方式是当①(绿色)返回结果时不告诉redis队列,而是直接通讯websocket服务数据已经发生变化,再由websocket服务通知浏览器客户端重新加载。因为此种方案比较简单再加上swoole对一些操作的封装比较便利,这里就采用此种办法

  • 当websocket连接被打开时,向socket服务发送当前注册id,因为只有这样websocket服务才能定向的为指定连接发送数据
ws.onopen = function(){
    console.log("socket连接已打开");
    $.post(‘/mercha/merchant/find‘,function(d){ //从web服务端获取注册id
        d = $.parseJSON(d);
        ws.send("merchantId_"+d.data.id);
    })
};
  • 当websocket服务收到注册id时会将当前连接的id和由服务端传来的商户id对应关系写入redis
$server->on(‘Message‘, function ($serv, $frame) {
    if(stripos($frame->data,‘merchantId_‘) !== false){

        $fd = $redis->get($frame->data);
        if($fd != null){
            $fd = json_decode($fd,true);
        }

        //这里的$frame->fd是指当前的websocket连接id,swoole会通过此id发送给对应的接收方,可以理解为手机号码
        $fd[$frame->fd] = $frame->fd;
        $fd = json_encode($fd);
        $redis->set($frame->data,$fd);
    }
});
  • 因为swoole_websocket_server 继承自 swoole_http_server ,这样就可以通过http的方式和websocket服务进行交互
$server->on(‘Request‘, function ($req, $respone) {

    if(isset($req->get[‘merchantId‘])){
        global $server;
        global $redis;

        $merchantId = $req->get[‘merchantId‘];
        $fd = $redis->get("merchantId_".$merchantId);
        if($fd != null){
            $fd = json_decode($fd,true);
        }

        $err = 0;
        if(is_array($fd)){
            foreach($fd as $f){
                $res = @$server->push($f, "refresh");
                if($res === false){
                    unset($fd[$f]);
                    $err++;
                }
            }

            if($err){
                $fd = json_encode($fd);
                $redis->set("merchantId_".$merchantId,$fd);
            }
        }
    }

    $respone->end("success");
});

** 需要强调的一点是监听http请求的server并不具备push方法,所以这里通过全局变量的方式使用websocket的$server来向客户端发送数据 **

以上就是解决问题的大概思路了,文章最后会附上websocket的服务端源码,因为业务稍多所以里面集成了很多业务代码,而且需要运行起来必须要先安装swoole的扩展,安装方式上篇文章会有说明,所以这里仅供参考

对于图中另一种使用redis的方式也是很好的,之前采用了redis发布订阅的模式基本可以达到想要的效果。但是中间遇到一个问题redis的subscribe运行几十秒后,就会抛出一个RedisException。原因处在于,php的redis库使用的subscribe是使用PHP内置的socket,而php.ini默认是设置了socket的超时时间是60秒,所以大家只要找到default_socket_timeout 这个配置项,把时间改长点就可以了。或者在代码中加入ini_set(‘default_socket_timeout‘, -1);

websocket服务端源码

http://www.cnblogs.com/JasonLeemz/p/5116814.html

时间: 2024-08-08 01:26:29

使用php+swoole对client数据实时更新(二) (转)的相关文章

基于server broker 的数据实时更新

Service Broker介绍:SQL Server Service Broker 为消息和队列应用程序提供 SQL Server 数据库引擎本机支持.这使开发人员可以轻松地创建使用数据库引擎组件在完全不同的数据库之间进行通信的复杂应用程序.开发人员可以使用 Service Broker 轻松生成可靠的分布式应用程序.使用 Service Broker 的应用程序开发人员无需编写复杂的内部通信和消息,即可跨多个数据库分发数据工作负荷.因为 Service Broker 会处理会话上下文中的通信

十三 .Flask wtforms组件和选择框动态数据实时更新

一 . wtforms组件     选择框动态数据实时更新 https://www.cnblogs.com/lovershowtime/p/11384494.html 1.wtforms组件使用(登录) 1. 用户登录 当用户登录时候,需要对用户提交的用户名和密码进行多种格式校验.如: 用户不能为空:用户长度必须大于6: 密码不能为空:密码长度必须大于12:密码必须包含 字母.数字.特殊字符等(自定义正则): login.html <!DOCTYPE html> <html lang=&

form 内置字段,数据实时更新,下拉框

用来验证 和 显示 生成html代码 类创建字段 使用参数 Field函数 required=True, 是否允许为空 widget=None, HTML插件 label=None, 用于生成Label标签或显示内容 initial=None, 初始值 help_text='', 帮助信息(在标签旁边显示) error_messages=None, 错误信息 {'required': '不能为空', 'invalid': '格式错误'} show_hidden_initial=False, 是否

Qt之模型/视图(实时更新数据)

上两节简单介绍了Qt中对于模型/视图的编程,大部分助手里说的很清楚了,现在就开始实战部分吧! 在实际应用中,视图展示的数据往往并非一成不变的,那么如何实时更新成了一个很重要的问题!功能:(1)添加委托(进度条)(2)显示文件名称.大小.进度.速度.剩余时间.状态等.(3)可进行添加.更新.删除.清空等操作.(4)实时更新数据先看一个效果图:委托(进度条):ProgressBarDelegate::ProgressBarDelegate(QObject *parent): QItemDelegat

php+ajax实现答题总量数据的实时更新

背景:最近给我们学生处搭建了一个新生学生手册考试平台.平台使用人数差不多达到近5000余人.自由练习模块几乎是每时每刻都有人在做题.于是好奇心颇强的我就写了个答题总量数据的事实更新.做成之后的效果如下:http://newer.gailvlunpt.com/EntranceEducation/admin.php/Statis/sum 看着每时每刻都在增长的答题数据,心中未免不欣喜. 涉及到的技术:前台网页用javascipt+ajax每隔2秒钟请求后台服务器数据.后台接口是统计数据库答题总量.

WebSocket 实时更新mysql数据到页面

使用websocket的初衷是,要实时更新mysql中的报警信息到web页面显示 没怎么碰过web,代码写的是真烂,不过也算是功能实现了,放在这里也是鞭策自己,web也要多下些功夫 准备 引入依赖 <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.38</version> <

实时更新数据,无需刷新:a,如何使用Turbolinks clearCache(), b Action Cable

https://gorails.com/episodes/how-to-use-turbolinks-clearCache?autoplay=1 用途: 更方便的实时从服务器更新局部网页,在这页更新了一条记录的显示方式, 再打开的之前网页的相同位置或相同的功能模块显示也会同步更新. 把Turbolinks.clearCache(), Turbolinks.clearCache(); 比如放在你写的xx.js.erb的第一行. 如果不加这句话,turbolinks只会reload之前的网页中的数据

C# chart 关于实时更新传感器数据

因为自己毕业需要做一个有关环境监测的项目,原理是通过无线采集环境信息,将信息实时保存到数据库,上位机是winform程序,程序需要实时的显示已经采集到的数据,并用曲线的方式表现出来,自己折腾了几天,也算是有一些小的收货,自己也是刚接触C#编程,给我的感觉非常的好. 用到的chart控件下载地址  链接: http://pan.baidu.com/s/1eSnYj3W 密码: xqhm 我用的是VS2010. 分析我的目的要求:实时刷新获取数据库的数据,将数据实时的显示到chart表上. 我的解决

8086汇编学习小结———实时更新

初学IBM-PC 8086,对INT指令不是很理解.现从网上总计如下: 表:DOS系统功能调INT 21H AH 功能 调用参数 返回参数 00 程序终止(同INT 20H) CS=程序段前缀 01 键盘输入并回显 AL=输入字符 02 显示输出 DL=输出字符 03 异步通迅输入 AL=输入数据 04 异步通迅输出 DL=输出数据 05 打印机输出 DL=输出字符 06 直接控制台I/O DL=FF(输入)DL=字符(输出) AL=输入字符 07 键盘输入(无回显) AL=输入字符 08 键盘