我们目前的大多数应用都是以服务端+接口+客户端的方式去协调工作的,这样的好处在于不论是处在何种终端的情况下,都可以完美的和服务端兼容。这样就轻松实现了MVC各个部分的真正解耦。但是提高程序的友好性还是有很多路要走,其中一个大家都会遇到的就是数据实时更新的问题。比如一个用户在手机上做了添加操作,这时候其他的终端也应该及时显示数据的变化情况。这个对于手机来说还算好办,因为现在的各种推送服务完全可以满足需求,当收到推送更新时,根据推送内容请求相应接口就可以了。但是放到PC上就不是这么回事了。浏览器和http协议的特殊性质不得不让我们另辟蹊径。
举一个大家生活中都会遇到的场景: ** 针对上述的情景呢,这里有一个系统间交互的流程图:**
下面一行是其他用户也正在操作同一条数据。当①(绿色)返回结果时,web服务器会同时告诉当前用户和redis队列服务(①黄色),因为websocket服务实时监听redis,这样一旦有数据变化,websocket服务会及时感知。此时通过与浏览器建立的长连接进行通讯并告知数据已经更新并重新加载。 另外一种方式是当①(绿色)返回结果时不告诉redis队列,而是直接通讯websocket服务数据已经发生变化,再由websocket服务通知浏览器客户端重新加载。因为此种方案比较简单再加上swoole对一些操作的封装比较便利,这里就采用此种办法
ws.onopen = function(){ console.log("socket连接已打开"); $.post('/mercha/merchant/find',function(d){ //从web服务端获取注册id d = $.parseJSON(d); ws.send("merchantId_"+d.data.id); }) };
$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); } });
$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来向客户端发送数据 **
(责任编辑:最模板) |