上一篇提到了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

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

  1. 使用php+swoole对client数据实时更新(上)

    如果想对一个列表做实时的更新,传统的做法是采用轮询的方式.以web为例,通过Ajax定时请求服务端然后获取数据显示在页面.这种方式实现简单,缺点就是浪费资源. HTTP1.1新增加了对websocke ...

  2. 使用php+swoole对client数据实时更新(下)

    上一篇提到了swoole的基本使用,现在通过几行基本的语句来实现比较复杂的逻辑操作: 先说一下业务场景.我们目前的大多数应用都是以服务端+接口+客户端的方式去协调工作的,这样的好处在于不论是处在何种终 ...

  3. MySQL 实现将一个库表里面的数据实时更新到另一个库表里面

    MySQL 实现将一个库表里面的数据实时更新到另一个库表里面 需求描述:MySQL 里面有很多的数据库,这些数据库里面都有同一种表结构的表 (tb_warn_log),这张表的数据是实时更新的,现在需 ...

  4. Web网站数据”实时”更新设计

    请注意这个实时打上了双引号,没有绝对的实时,只是时间的颗粒不一样罢了(1ms,1s,1m). 服务器数据有更新可以快速通知客户端.Web 基于取得模式,而服务器建立大量的和客户端连接来提供数据实时更新 ...

  5. 基于server broker 的数据实时更新

    Service Broker介绍:SQL Server Service Broker 为消息和队列应用程序提供 SQL Server 数据库引擎本机支持.这使开发人员可以轻松地创建使用数据库引擎组件在 ...

  6. vue 跳转并传参,实现数据实时更新

    原文链接:点我 比如我现在在页面A跳转到页面B,A中的router-link :to={path:’B’,params:{id:’5’}} 求助:在页面B中的mounted生命周期函数中使用this. ...

  7. MFC编辑框数据实时更新问题

    在VC里,很多情况下需要更新控件,也就是调用UpdateData(FALSE);但是如果是在循环中调用该函数,会导致没有时间来刷新界面,消息得不到相应,从外部看来,似乎整个循环只执行了一次Update ...

  8. IDEA 修改JSP和后端数据后,页面刷新可以实时更新

    情况:刚开始使用IDEA进行开发时,发现修改JSP页面或者后端数据后,再刷新浏览器页面,发现没有变化,页面无更新. 这样就导致不得不频繁重启tomcat服务器.非常麻烦 解决方法: 步骤1. 先设置t ...

  9. Tornado实现监控数据实时展示

    前言: It has been a while since I last updated my blogs. 使用Tornado开发一个实时监控信息系统,其中包括 CUP.内存.网卡.磁盘使用率. 涉 ...

随机推荐

  1. 探索Oracle数据库升级6 11.2.0.4.3 Upgrade12c(12.1.0.1)

    探索Oracle数据库升级6 11.2.0.4.3 Upgrade12c(12.1.0.1) 一.前言:       Oracle 12c公布距今已经一年有余了,其最大亮点是一个能够插拔的数据库(PD ...

  2. 【原创】最近写的一个比较hack的小爬虫

    目标:爬取爱漫画上面自己喜欢的一个漫画 分析阶段: 0.打开爱漫画主页,迎面就是一坨js代码..直接晕了 1.经过抓包和对html源码的分析,可以发现爱漫画通过另外一个域名发送图片,而当前域名中通过j ...

  3. SQL Server中的查询

          本博文简介一下SQL Server中经常使用的几类查询及相关使用的方法.       一.ExecuteScalar方法获取单一值       ExecuteScalar方法是SqlCom ...

  4. Oracle外键(Foreign Key)使用详细的说明(一)

    Oracle外键(Foreign Key)使用详细的说明(一) 1.目标 演示如何Oracle使用外键数据库 2.什么是外键? 1)在Oracle数据库中,外键是用来实现參照完整性的方法之中的一个.打 ...

  5. java 对map排序

    public static Map<String, String> sortMapByKey(Map<String, String> map) { if (map == nul ...

  6. 三种方法让你的Service不被“一键加速”和系统杀掉

    基本上大家都知道提高service优先级能够在非常大程度上让你的service免于由于内存不足而被kill,当然系统仅仅是在此时先把优先级低的kill掉,假设内存还是不够,也会把你的service干掉 ...

  7. Shell 遍历字符串与参数

    遍历字符串: for line in  $Table_List do         echo $Table_List         echo $Table_List >> ${SYB_ ...

  8. 关于VCL的编写 (一) 如何编写自己的VCL控件

    如何编写自己的VCL控件 用过Delphi的朋友们,大概对Delphi的最喜欢Delphi的不是他的强类型的pascal语法,而是强大的VCL控件,本人就是一位VCL控件的爱好者. VCL控件的开源, ...

  9. Fire Net HDU

    Fire Net Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 65536/32768K (Java/Other) Total Subm ...

  10. 乐在其中设计模式(C#) - 提供者模式(Provider Pattern)

    原文:乐在其中设计模式(C#) - 提供者模式(Provider Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 提供者模式(Provider Pattern) 作者:weba ...