上一篇提到了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服务端源码

使用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. Spring 框架的架包分析、功能作用、优点,及jar架包简介

    Spring 框架的架包详解    Spring的作用     Spring的优势  由于刚搭建完一个MVC框架,决定分享一下我搭建过程中学习到的一些东西.我觉得不管你是个初级程序员还是高级程序员抑或 ...

  2. Warning: strftime(): It is not safe to rely on the system's timezone settings.

    当运行程序时,会出现如下警告: Warning: strftime(): It is not safe to rely on the system's timezone settings. You a ...

  3. [LeetCode] Verify Preorder Sequence in Binary Search Tree 验证二叉搜索树的先序序列

    Given an array of numbers, verify whether it is the correct preorder traversal sequence of a binary ...

  4. electron 入门小白贴

    electron 入门小白贴 electron demo 跑起来! 毕设准备是做个 跨平台的做题的客户端,打算用 electron 来弄. 然而今天折腾了半天才终于吧demo给跑起来了.经历了许多的问 ...

  5. 在windows上部署使用Redis

    参考地址: http://keenwon.com/1275.html

  6. Scrum Meeting

    本周Sprint Master 侯宇泰 一. 工作完成内容记录 & 明日计划 · 陈双: 完成内容: 1. 做了一个英语趣配音的用户评价调研 2. 上传了一个新视频 明日计划: 1. 与前端录 ...

  7. 【总结】.Net面试题集锦 (二)

    一.前面的话 本文的面试题不是很难,这里只是想记录个人的思考过程,另一方面希望有更好的解决办法的大牛留下宝贵的思路,大家共同学习进步. 二.题目 思路:第一步:把一维数组的值和次数存入Dictiona ...

  8. pycharm5注册码

    43B4A73YYJ-eyJsaWNlbnNlSWQiOiI0M0I0QTczWVlKIiwibGljZW5zZWVOYW1lIjoibGFuIHl1IiwiYXNzaWduZWVOYW1lIjoiI ...

  9. BZOJ1013: [JSOI2008]球形空间产生器sphere

    传送门 高斯消元练习. 模板: void Guass(){ int waited; up(i,1,N){ waited=i; up(j,i+1,N)if(fabs(M[j][i])>fabs(M ...

  10. MVC分页

    http://www.cnblogs.com/iamlilinfeng/p/4075292.html 目录 一.Contrl与View数据传递(多表数据) 二.分页控件介绍 三.MVC源码说明 四.源 ...