使用php+swoole对client数据实时更新(二)_html/css_WEB-ITnose
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了使用php+swoole对client数据实时更新(二)_html/css_WEB-ITnose,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含4092字,纯文字阅读大概需要6分钟。
内容图文
![使用php+swoole对client数据实时更新(二)_html/css_WEB-ITnose](/upload/InfoBanner/zyjiaocheng/408/c26f0d04186c481cb2068f8f563faf6b.jpg)
先说一下业务场景。我们目前的大多数应用都是以服务端+接口+客户端的方式去协调工作的,这样的好处在于不论是处在何种终端的情况下,都可以完美的和服务端兼容。这样就轻松实现了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数据实时更新(二)_html/css_WEB-ITnose全部内容,希望文章能够帮你解决使用php+swoole对client数据实时更新(二)_html/css_WEB-ITnose所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。