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

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 上一篇提到了swoole的基本使用,现在通过几行基本的语句来实现比较复杂的逻辑操作: 先说一下业务场景。我们目前的大多数应用都是以服务端+接口+客户端的方式去协调工作的,这样的好处在于不论是处在何种终端的情况下,都可以完美的和服务端兼容。

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

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

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

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

https://yqfile.alicdn.com/img_0b5bcf1d0a596d6ffd301f6f33e8678b.jpg)

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

下面一行是其他用户也正在操作同一条数据。当①(绿色)返回结果时,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

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
相关文章
|
3月前
|
JSON 数据处理 PHP
PHP数组处理技巧:高效操作数据集合
PHP数组处理技巧:高效操作数据集合
|
3月前
|
JSON 安全 大数据
PHP中的数组处理艺术:灵活高效的数据操作
PHP中的数组处理艺术:灵活高效的数据操作
|
20天前
|
消息中间件 NoSQL 调度
温故而知新,PHP Swoole使用过程中的一些思考
本文回顾了异步任务处理、进程与协程调度机制、Redis与消息队列的应用、Swoole协程原理等内容,探讨了CPU时间片分配、IO阻塞、协程切换等关键技术问题,适用于高并发场景下的性能优化与系统设计。
|
3月前
|
JSON 定位技术 PHP
PHP技巧:解析JSON及提取数据
这就是在PHP世界里探索JSON数据的艺术。这场狩猎不仅仅是为了获得数据,而是一种透彻理解数据结构的行动,让数据在你的编码海洋中畅游。通过这次冒险,你已经掌握了打开数据宝箱的钥匙。紧握它,让你在编程世界中随心所欲地航行。
142 67
|
6月前
|
数据库连接 PHP 数据库
【YashanDB知识库】PHP使用ODBC驱动无法获取长度为256char以上的数据
【YashanDB知识库】PHP使用ODBC驱动无法获取长度为256char以上的数据
|
6月前
|
Oracle 关系型数据库 MySQL
【YashanDB知识库】php查询超过256长度字符串,数据被截断的问题
本文分析了YashanDB中PHP通过ODBC查询数据时出现的数据截断问题,表现为超过256字节的数据被截断,以及isql工具无法显示超过300字节长度的数据。问题根源在于YashanDB的ODBC驱动仅支持单次查询,且PHP扩展库默认缓冲区限制。解决方案包括改用PHP ODBC扩展库而非PDO_ODBC,以及调整isql代码逻辑以支持循环取数或一次性读取完整数据。文章还提供了具体代码示例和规避方法,适用于23.2.4.14及更早版本。
【YashanDB知识库】php查询超过256长度字符串,数据被截断的问题
|
7月前
|
Oracle 关系型数据库 MySQL
【YashanDB 知识库】php 查询超过 256 长度字符串,数据被截断的问题
php 查询超过 256 字节数据,显示被截断:yashandb 的 odbc 驱动接口 SQLGetData 现在只支持单次查询,不支持多次取数据的操作。 isql 显示不出来,isql 工具最大只查询 300 长度的数据,超过了该长度未正常显示。
|
10月前
|
数据采集 JSON JavaScript
如何通过PHP爬虫模拟表单提交,抓取隐藏数据
本文介绍了如何使用PHP模拟表单提交并结合代理IP技术抓取京东商品的实时名称和价格,特别是在电商大促期间的数据采集需求。通过cURL发送POST请求,设置User-Agent和Cookie,使用代理IP绕过限制,解析返回数据,展示了完整代码示例。
204 3
如何通过PHP爬虫模拟表单提交,抓取隐藏数据
|
10月前
|
缓存 NoSQL PHP
Redis作为PHP缓存解决方案的优势、实现方式及注意事项。Redis凭借其高性能、丰富的数据结构、数据持久化和分布式支持等特点,在提升应用响应速度和处理能力方面表现突出
本文深入探讨了Redis作为PHP缓存解决方案的优势、实现方式及注意事项。Redis凭借其高性能、丰富的数据结构、数据持久化和分布式支持等特点,在提升应用响应速度和处理能力方面表现突出。文章还介绍了Redis在页面缓存、数据缓存和会话缓存等应用场景中的使用,并强调了缓存数据一致性、过期时间设置、容量控制和安全问题的重要性。
179 5
|
10月前
|
XML 前端开发 JavaScript
PHP与Ajax在Web开发中的交互技术。PHP作为服务器端脚本语言,处理数据和业务逻辑
本文深入探讨了PHP与Ajax在Web开发中的交互技术。PHP作为服务器端脚本语言,处理数据和业务逻辑;Ajax则通过异步请求实现页面无刷新更新。文中详细介绍了两者的工作原理、数据传输格式选择、具体实现方法及实际应用案例,如实时数据更新、表单验证与提交、动态加载内容等。同时,针对跨域问题、数据安全与性能优化提出了建议。总结指出,PHP与Ajax的结合能显著提升Web应用的效率和用户体验。
217 3