首页 > 作文

Laravel 中使用 swoole 项目实战开发案例二 (后端主动分场景给界面推送消息)

更新时间:2023-04-08 00:09:23 阅读: 评论:0

推荐阅读:laravel 中使用 swoole 项目实战开发案例一 (建立 swoole 和前端通信)

需求分析

我们假设有一个需求,我在后端点击按钮 1,首页弹出 “后端触发了按钮 1”。后端点了按钮 2,列表页弹出 “后端触发了按钮 2”。做到根据不同场景推送到不同页面。

代码思路

swoole fd
客户端浏览器打开或者刷新界面,在 swoole 服务会生成一个进程句柄fd,每次浏览器页面有打开链接 websocket 的 js 代码,便会生成,每次刷新的时候,会关闭之前打开的fd,重新生成一个新的,关闭界面的时候会生成一个新的。swoole 的fd生成规则是从 1 开始递增。redis hash 存储 fd
我们建立一个 key 为swoole:fdsredis 哈希类型数据,fd为 hash 的字段,每个字段的值我们存储前端 websocket 请求的 url 参数信息 (根据业务复杂度自己灵活变通,我在项目中会在 url 带上 ssionid)。每次链接打开 swoole 服务的时候我们存储其信息,每次关闭页面时候我们清除其字段。在 redis 存储如下

触发分场景推送
在界面上当进行了触发操作的时候,通过后台 curl 请求 swoole http 服务,swoole http 服务根据你向我传递的参数分发给对应的逻辑处理。如 curl 请求127.0.0.1:9502page=back&func=pushhomelogic&token=123456我们可以根据传入的func参数,在后台分发给对应逻辑处理。如分发给pushhomelogic方法。在其里面实现自己的逻辑。为防止过多的ifel以及foreach 操作,我们采用的是闭包,call_ur_func等方法实现如下

 1 public function onrequest($request,$respon) 2 { 3     if ($this->checkaccess("", $request)) { 4         $param = $request->get; 5         // 分发处理请求逻辑 6         if (ist($param['func'])) { 7             if (method_exists($this,$param['func'])) { 8                 call_ur_func([$this,$param['func']],$request); 9             }10         }11     }12 }// 往首页推送逻辑处理13 public function pushhomelogic($request)14 {15     $callback = function (array $acontent,int $fd,swooledemo $oswoole)u($request) {16         if ($acontent && $acontent['page'] == "home") {17             $ares['message'] = "后端按了按钮1";18             $ares['code'] = "200";19             $oswoole::$rver->push($fd,xss_json($ares));20         }21     };22     $this->eachfdlogic($callback);23 }

完整代码

swool 脚本代码逻辑

  1 <?php  2   3 namespace app\console\commands;  4   5 u closure;  6 u illuminate\console\command;  7 u illuminate\support\facades\redis;  8   9 class swooledemo extends command 10 { 11     // 命令名称 12     protected $signature = 'swoole:demo'; 13     // 命令说明 14     protected $description = '这是关于swoole websocket的一个测试demo'; 15     // swoole websocket服务 16     private static $rver = null; 17  18     public function __construct() 19     { 20         parent::__construct(); 21     } 22  23     // 入口 24     public function handle() 25     { 26         $this->redis = redis::connection('websocket'); 27         $rver = lf::getwebsocketrver(); 28         $rver->on('open',[$this,'onopen']); 29         $rver->on('message', [$this, 'onmessage']); 30         $rver->on('clo', [$this, 'onclo']); 31         $rver->on('request', [$this, 'onrequest']); 32         $this->line("swoole服务启动成功 ..."); 33         $rver->start(); 34     } 35  36     // 获取服务 37     public static function getwebsocketrver() 38     { 39         if (!(lf::$rver instanceof \swoole_websocket_rver)) { 40             lf::twebsocketrver(); 41         } 42         return lf::$rver; 43     } 44     // 服务处始设置 45     protected static function twebsocketrver():void 46     { 47         lf::$rver  = new \swoole_websocket_rver("0.0.0.0", 9502); 48         lf::$rver->t([ 49             'worker_num' => 1, 50             'heartbeat_check_interval' => 60,    // 60秒检测一次 51             'heartbeat_idle_情人节甜言蜜语time' => 121,        // 121秒没活动的 52         ]); 53     } 54  55     // 打开swoole websocket服务回调代码 56     public function onopen($rver, $request) 57     { 58         if ($this->checkaccess($rver, $request)) { 59             lf::$rver->push($request->fd,xss_json(["code"=>200,"message"=>"打开swoole服务成功"])); 60         } 61     } 62     // 给swoole websocket 发送消息回调代码 63     public function onmessage($rver, $frame) 64     { 65  66     } 67     // http请求swoole websocket 回调代码 68     public function onrequest($request,$respon) 69     { 70         if ($this->checkaccess("", $request)) { 71             $param = $request->get; 72             // 分发处理请求逻辑 73             if (ist($param['func'])) { 74                 if (method_exists($this,$param['func'])) { 75                     call_ur_func([$this,$param['func']],$request); 76                 } 77             } 78         } 79     } 80  81     // websocket 关闭回调代码 82     public function onclo($rv,$fd) 83     { 84         $this->redis->hdel('swoole:fds', $fd); 85         $this->line("客户端 {$fd} 关闭"); 86     } 87  88     // 校验客户端连接的合法性,无效的连接不允许连接 89     public function checkaccess($rver, $request):bool 90     { 91         $bres = true; 92         if (!ist($request->get) || !ist($request->get['token'])) { 93             lf::$rver->clo($request->fd); 94             $this->line("接口验证字段不全"); 95             $bres = fal; 96         } el if ($request->get['token'] != 123456) { 97             $this->line("接口验证错误"); 98             $bres = fal; 99         }100         $this->storeurlparamtoredis($request);101         return $bres;102     }103 104     // 将每个界面打开websocket的url 存储起来105     public function storeurlparamtoredis($request):void106     {107         // 存储请求url带的信息108         $scontent = json_encode(109             [110                 'page' => $request->get['page'],111                 'fd' => $request->fd,112             ], true);113         $this->redis->ht("swoole:fds", $request->fd, $scontent);114     }115 116     /**117      * @param $request118      * @e 循环逻辑处理119      */120     public function eachfdlogic(closure $callback = null)121     {122         foreach (lf::$rver->connections as $fd) {123             if (lf::$rver->istablished($fd)) {124                 $acontent = json_decode($this->redis->hget("swoole:fds",$fd),true);125                 $callback($acontent,$fd,$this);126             } el {127                 $this->redis->hdel("swoole:fds",$fd);128             }129         }130     }131     // 往首页推送逻辑处理132     public function pushhomelogic($request)133     {134         $callback = function (array $acontent,int $fd,swooledemo $oswoole)u($request) {135             if ($acontent && $acontent['page'] == "home") {136                 $ares['message'] = "后端按了按钮1";137                 $ares['code'] = "200";138                 $oswoole::$rver->push($fd,xss_json($ares));139             }140         };141         $this->eachfdlogic($callback);142     }143     // 往列表页推送逻辑处理144     public function pushlistlogic($request)145     {146         $callback = function (array $acontent,int $fd,swooledemo $oswoole)u($request) {147             if ($acontent && $acontent['page'] == "list") {148                 $ares['message'] = "后端按了按钮2";149                 $ares['code'] = "200";150                 $oswoole::$rver->push($fd,xss_json($ares));151             }152         };153         $this->eachfdlogic($callback);154     }155 156     // 启动websocket服务157     public function start()158     {159         lf::$rver->start();160     }161 }162 控制器代码163 164 <?php165 166 namespace app\http\controllers;167 168 u illuminate\http\request;169 u illuminate\support\facades\redis;170 class testcontroller extends controller171 {172     // 首页173     public function home()174     {175         return view江苏新高考("home");176     }177     // 列表178     public function list()179     {180         return view("list");181     }182     // 后端控制183     public function back()184     {185         if (request()->method() == 'post') {186            $this->curl_get($this->geturl());187            return json_encode(['code'=>200,"message"=>"成功"]);188         } el {189             return view("back");190         }191 192     }193     // 获取要请求swoole websocet服务地址194     public function geturl():string195     {196         // 域名 端口 请求swoole服务的方法197         $sba = request()->rver('http_host');198         $iport = 9502;199         $sfunc = request()->post('func');200         $spage = "back";201         return $sba.":".$iport."?func=".$sfunc."&token=123456&page=".$spage;202     }203     // curl 推送204     public function cu北京舞蹈培训rl_get(string $url):string205     {206         $ch_curl = curl_init();207         curl_topt ($ch_curl, curlopt_timeout_ms, 3000);208         curl_topt($ch_curl, curlopt_ssl_verifypeer, 0);209         curl_topt ($ch_curl, curlopt_header,fal);210         curl_topt($ch_curl, curlopt_httpget, 1);211         curl_topt($ch_curl, curlopt_returntransfer,true);212         curl_topt ($ch_curl, curlopt_url,$url);213         $str  = curl_exec($ch_curl);214         curl_clo($ch_curl);215         return $str;216     }217 }

页面 js 代码

后端控制页
 1 <!doctype html> 2 <html lang="en"> 3 <head> 4 <meta chart="utf-8"> 5 <title>后端界面</title> 6 <meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,ur-scalable=no"> 7 </head> 8 <body> 9 <button class="push" data-func="pushhomelogic">按钮1</button>10 <button class="push" data-func="pushlistlogic">按钮2</button>11 </body>12 <script src="{{ ast("/vendor/tw/global/jquery/jquery-2.2.3.min.js")}} "></script>13 <script>14 $(function () {15     $(".push").on('click',function(){16         var func = $(this).attr('data-func').trim();17         ajaxget(func)18     })19     function ajaxget(func) {20         url = "{{route('back')}}";21         token = "{{csrf_token()}}";22         $.ajax({23             url: url,24             type: 'post',25             datatype: "json",26             data:{func:func,_token:token},27             error: function (data) {28                 alert("服务器繁忙, 请联系管理员!");29                 return;30             },31             success: function (result) {32 33             },34         })35     }36 37 })38 </script>39 </html>

首页

 1 <!doctype html> 2 <html lang="en"> 3 <head> 4 <meta chart="utf-8"> 5 <title>swoole首页</title> 6 <meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,ur-scalable=no"> 7 </head> 8 <body> 9 <h1>这是首页</h1>10 </body>11 <script>12 var ws;//websocket实例13 var lockreconnect = fal;//避免重复连接14 var wsurl = 'ws://{{$_rver["http_host"]}}:9502?page=home&token=123456';15 16 function initeventhandle() {17     ws.onclo = function () {18         reconnect(wsurl);19     };20     ws.onerror = function () {21         reconnect(wsurl);22     };23     ws.onopen = function () {24         //心跳检测重置25         heartcheck.ret().start();26     };27     ws.onmessage = function (event) {28         //如果获取到消息,心跳检测重置29         //拿到任何消息都说明当前连接是正常的30         var data = json.par(event.data);31         if (data.code == 200) {32             console.log(data.message)33         }34         heartcheck.ret().start();35     }36 }37 createwebsocket(wsurl);38 /**39  * 创建链接40  * @param url41  */42 function createwebsocket(url) {43     try {44         ws = new websocket(url);45         initeventhandle();46     } catch (e) {47         reconnect(url);48     }49 }50 function reconnect(url) {51     if(lockreconnect) return;52     lockreconnect = true;53     //没连接上会一直重连,设置延迟避免请求过多54     ttimeout(function () {55         createwebsocket(url);56         lockreconnect = fal;57     }, 2000);58 }59 //心跳检测60 var heartcheck = {61     timeout: 60000,//60秒62     timeoutobj: null,63     rvertimeoutobj: null,64     ret: function(){65         cleartimeout(this.timeoutobj);66         cleartimeout(this.rvertimeoutobj);67         return this;68     },69     start: function(){70         var lf = this;71         this.timeoutobj = ttimeout(function(){72             //这里发送一个心跳,后端收到后,返回一个心跳消息,73             //onmessage拿到返回的心跳就说明连接正常74             ws.nd("heartbeat");75             lf.rvertimeoutobj = ttimeout(function(){//如果超过一定时间还没重置,说明后端主动断开了76                 ws.clo();//如果onclo会执行reconnect,我们执行ws.clo()就行了.如果直接执行reconnect 会触发onclo导致重连两次77             }, lf.timeout);78         }, this.timeout);79     },80     header:function(url) {81         window.location.href=url82     }83 84 }85 </script>86 </html>

列表页面

 1 <!doctype html> 2 <html lang="en"> 3 <head> 4 <meta chart="utf-8"> 5 <title>swoole列表页</title> 6 <meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,ur-scalable=no"> 7 </head> 8 <body> 9 <h1>swoole列表页</h1>10 </body>11 <script>12 var ws;//websocket实例13 var lockreconnect = fal;//避免重复连接14 var wsurl = 'ws://{{$_rver["http_host"]}}:9502?page=list&token=123456';15 16 function initeventhandle() {17     ws.onclo = function () {18         reconnect(wsurl);19     };20     ws.onerror = function () {21         reconnect(wsurl);22     };23     ws.onopen = function () {24         //心跳检测重置25         heartcheck.ret().start();26     };27     ws.onmessage = function (event) {28         //如果获取到消息,心跳检测重置29         //拿到任何消息都说明当前连接是正常的30         var data = json.par(event.data);31         if (data.code == 200) {32             console.log(data.message)33         }34         heartcheck.ret().start();35     }36 }37 createwebsocket(wsurl);38 /**39  * 创建链接40  * @param url41  */42 function createwebsocket(url) {43     try {44         ws = new websocket(url);45         initeventhandle();46     } catch (e) {47         reconnect(url);48     }49 }50 function reconnect(url) {51     if(lockreconnect) return;52     lockreconnect = true;53     //没连接上会一直重连,设置延迟避免请求过多54     ttimeout(function () {55         createwebsocket(url);56         lockreconnect = fal;57     }, 2000);58 }59 //心跳检测60 var heartcheck = {61     timeout: 60000,//60秒62     timeoutobj: null,63     rvertimeoutobj: null,64     ret: function(){65         cleartimeout(this.timeoutobj);66         cleartimeout(this.rvertimeoutobj);67         return thisyb创业计划书s;68     },69     start: function(){70         var lf = this;71         this.timeoutobj = ttimeout(function(){72             //这里发送一个心跳,后端收到后,返回一个心跳消息,73             //onmessage拿到返回的心跳就说明连接正常74             ws.nd("heartbeat");75             lf.rvertimeoutobj = ttimeout(function(){//如果超过一定时间还没重置,说明后端主动断开了76                 ws.clo();//如果onclo会执行reconnect,我们执行ws.clo()就行了.如果直接执行reconnect 会触发onclo导致重连两次77             }, lf.timeout);78         }, this.timeout);79     },80     header:function(url) {81         window.location.href=url82     }83 84 }85 </script>86 </h挂职锻炼tml>

界面效果

后台控制点击按钮 1

后端界面点击按钮 2

本文发布于:2023-04-08 00:09:21,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/zuowen/d3c89eaf35e75ec533b2654cad9688f3.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

本文word下载地址:Laravel 中使用 swoole 项目实战开发案例二 (后端主动分场景给界面推送消息).doc

本文 PDF 下载地址:Laravel 中使用 swoole 项目实战开发案例二 (后端主动分场景给界面推送消息).pdf

标签:后端   按钮   逻辑   代码
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图