基于workerman的实时推送,摒弃ajax轮询
先扯些这些内容:
TCP/IP
workerman是啥子?Workerman是一款纯PHP开发的开源高性能的PHP socket 服务器框架。被广泛的用于手机app、移动通讯,微信小程序,手游服务端、网络游戏、PHP聊天室、硬件通讯、智能家居、车联网、物联网等领域的开发。 支持TCP长连接,支持Websocket、HTTP等协议,支持自定义协议。拥有异步Mysql、异步Redis、异步Http、异步消息队列等众多高性能组件。
开始步入正题:为了达到实时通讯,很多时候我们采用了ajax轮询机制,如图:
后面可以采用workerman方式来实现,项目也是tp写的,官方手册这么说到 与其它mvc框架结合建议以上图的方式(ThinkPHP为例): 1、ThinkPHP与Workerman是两个独立的系统,独立部署(可部署在不同服务器),互不干扰。 2、ThinkPHP以HTTP协议提供网页页面在浏览器渲染展示。 3、ThinkPHP提供的页面的js发起websocket连接,连接workerman 4、连接后给Workerman发送一个数据包(包含用户名密码或者某种token串)用于验证websocket连接属于哪个用户。 5、仅在ThinkPHP需要向浏览器推送数据时,才调用workerman的socket接口推送数据。 6、其余请求还是按照原本ThinkPHP的HTTP方式调用处理。 总结: 把Workerman作为一个可以向浏览器推送的通道,仅仅在需要向浏览器推送数据时才调用Workerman接口完成推送。业务逻辑全部在ThinkPHP中完成。 ok,到这里,把workerman容器跑起来,注意这里是CLI模式运行
然后再我们项目接收信息中这么玩,附上代码 <script> // 连接服务端 var socket = io('http://127.0.0.1:2120'); // uid可以是自己网站的用户id,以便针对uid推送 uid = 123; // socket连接后以uid登录 socket.on('connect',function(){ socket.emit('login',uid); }); // 后端推送来消息时 socket.on('new_msg',function(msg){ console.log("收到消息:"+msg); //自己业务逻辑处理 }); </script> 接着,我们在用户向用户发送信息的时候添加 // 指明给谁推送,为空表示向所有在线用户推送 $to_uid = "123"; // 推送的url地址 $push_api_url = "http://127.0.0.1:2121/"; $post_data = array( "type" => "publish","content" => "数据","to" => $to_uid,); $ch = curl_init (); curl_setopt ( $ch,CURLOPT_URL,$push_api_url ); curl_setopt ( $ch,CURLOPT_POST,1 ); curl_setopt ( $ch,CURLOPT_HEADER,0 ); curl_setopt ( $ch,CURLOPT_RETURNTRANSFER,CURLOPT_POSTFIELDS,$post_data ); curl_setopt ($ch,CURLOPT_HTTPHEADER,array("Expect:")); $return = curl_exec ( $ch ); curl_close ( $ch ); var_export($return); 其中,workerman里面的推送核心代码实现 // 全局数组保存uid在线数据 $uidConnectionMap = array(); // 记录最后一次广播的在线用户数 $last_online_count = 0; // PHPSocketIO服务 $sender_io = new SocketIO(2120); // 客户端发起连接事件时,设置连接socket的各种事件回调 // 当$sender_io启动后监听一个http端口,通过这个端口可以给任意uid或者所有uid推送数据 $sender_io->on('workerStart',function(){ // 监听一个http端口 $inner_http_worker = new Worker('http://0.0.0.0:2121'); // 当http客户端发来数据时触发 $inner_http_worker->onMessage = function($http_connection,$data){ global $uidConnectionMap; $_POST = $_POST ? $_POST : $_GET; // 推送数据的url格式 type=publish&to=uid&content=xxxx switch(@$_POST['type']){ case 'publish': global $sender_io; $to = @$_POST['to']; $_POST['content'] = htmlspecialchars(@$_POST['content']); // 有指定uid则向uid所在socket组发送数据 if($to){ $sender_io->to($to)->emit('new_msg',$_POST['content']); // 否则向所有uid推送数据 }else{ $sender_io->emit('new_msg',@$_POST['content']); } // http接口返回,如果用户离线socket返回fail if($to && !isset($uidConnectionMap[$to])){ return $http_connection->send('offline'); }else{ return $http_connection->send('ok'); } } return $http_connection->send('fail'); }; }); if(!defined('GLOBAL_START')) { Worker::runAll(); } ok,大功告成! (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |