当前位置:首页 > CMS教程 > Thinkphp > 列表

ThinkPHP部署Workerman的成功使用示例

发布:smiling 来源: PHP粉丝网  添加日期:2023-10-06 17:07:07 浏览: 评论:0 

本文介绍thinkphp中关于composer集成workerman的方法,并解决了安装过程 中遇到的错误,实现了和woerkman进行握手和通信的demo,用户可以在此基础上按自己的逻辑实现一个聊天系统或者客服系统。

一、安装扩展包   composer require topthink/think-worker

直接执行:composer require topthink/think-worker=1.0.*     即可成功

二、新建 server.php

  1. #!/usr/bin/env php 
  2. <?php 
  3. define('APP_PATH', __DIR__ . '/application/'); 
  4. define('BIND_MODULE','push/Worker'); 
  5. // 加载框架引导文件 
  6. require __DIR__ . '/thinkphp/start.php'; 

三、新建Worker.php

php think make:controller push/Worker

即可,将里面的内容替换如下所示:

  1. <?php 
  2. namespace app\push\controller; 
  3. use think\Controller; 
  4. use think\Request; 
  5. use think\worker\Server; 
  6. use think\Cache; 
  7. class Worker extends Server 
  8. { 
  9.     protected $socket = 'websocket://0.0.0.0:2346'; 
  10.     protected $processes = 1; 
  11.     protected $uidConnections = array(); 
  12.     static $count  = 0; 
  13.     /** 
  14.      * 收到信息 
  15.      * @param $connection 
  16.      * @param $data 
  17.      */ 
  18.     public function onMessage($connection, $data) 
  19.     { 
  20.         $retdata=json_decode($data,true); 
  21.         $uid=$retdata['id']; 
  22.         $message=$retdata['msg']; 
  23.         if(isset($this->uidConnections[$uid])) 
  24.         { 
  25.             $connection = $this->uidConnections[$uid]; 
  26.             $connection->send($message); 
  27.             // return true; 
  28.         } 
  29.         $connection->send('我收到你的信息了333='.$retdata['msg']); 
  30.     } 
  31.     /** 
  32.      * 当连接建立时触发的回调函数 
  33.      * @param $connection 
  34.      */ 
  35.     public function onConnect($connection) 
  36.     { 
  37.         $this->uidConnections[$connection->id] = $connection; 
  38.         $connection->send('你连接了我='.$connection->id); 
  39.     } 
  40.     // 针对uid推送数据 
  41.     public function sendMessageByUid($uid, $message) 
  42.     { 
  43.         if(isset($this->uidConnections[$uid])) 
  44.         { 
  45.             $connection = $this->uidConnections[$uid]; 
  46.             $connection->send($message); 
  47.             return true; 
  48.         } 
  49.         return false; 
  50.     } 
  51.     /** 
  52.      * 当连接断开时触发的回调函数 
  53.      * @param $connection 
  54.      */ 
  55.     public function onClose($connection) 
  56.     { 
  57.     } 
  58.     /** 
  59.      * 当客户端的连接上发生错误时触发 
  60.      * @param $connection 
  61.      * @param $code 
  62.      * @param $msg 
  63.      */ 
  64.     public function onError($connection, $code, $msg) 
  65.     { 
  66.         echo "error $code $msg\n"; 
  67.     } 
  68.     /** 
  69.      * 每个进程启动 
  70.      * @param $worker 
  71.      */ 
  72.     public function onWorkerStart($worker) 
  73.     { 
  74.     } 
  75. } 

四、执行 php server.php start

遇到禁用函数就去对应的PHP里面把禁用函数删除 (此命令可以放到Supervisor的守护进程里面去),并且查看端口是否运行,宝塔里面也要放行对应的端口 2346

测试远程连接: telnet localhost 2346         localhost改成外网ip即可,这个走通了,前端就能直接连接了

linux 退出Telnet命令    先输入命令:CTRL+]然后再输入命令:quit

五、前端代码

  1. <!DOCTYPE html> 
  2. <html lang="en"> 
  3. <head> 
  4.     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
  5.     <title>Title</title> 
  6. </head> 
  7. <body> 
  8. <script> 
  9.     ws = new WebSocket("ws://118.**.***.207:2346"); 
  10.     ws.onopen = function() { 
  11.         console.log("连接成功"); 
  12.         ws.send('tom'); 
  13.         console.log("给服务端发送一个字符串:tom"); 
  14.     }; 
  15.     ws.onmessage = function(e) { 
  16.         console.log("收到服务端的消息:" + e.data); 
  17.     }; 
  18. </script> 
  19. </body> 
  20. </html> 

六、前端开两个端口即可进行相互通讯:

ws.send('{"id":"2","msg":"21111111111110"}');

重点在这:因为在这里需要用到服务端给客户端推送,用到了text服务

WorkerMan中php后端及时推送消息给客户端

原理:

1、建立一个websocket Worker,用来维持客户端长连接

2、websocket Worker内部建立一个text Worker

3、websocket Worker 与 text Worker是同一个进程,可以方便的共享客户端连接

4、某个独立的php后台系统通过text协议与text Worker通讯

5、text Worker操作websocket连接完成数据推送

代码及步骤

  1. //push.php 
  2. <?php 
  3. use Workerman\Worker; 
  4. require_once './vendor/workerman/workerman/Autoloader.php'; 
  5. // 初始化一个worker容器,监听1234端口 
  6. $worker = new Worker('websocket://0.0.0.0:1234');// 
  7. /* 
  8.  * 注意这里进程数必须设置为1,否则会报端口占用错误 
  9.  * (php 7可以设置进程数大于1,前提是$inner_text_worker->reusePort=true) 
  10.  */ 
  11. $worker->count = 1; 
  12. // worker进程启动后创建一个text Worker以便打开一个内部通讯端口 
  13. $worker->onWorkerStart = function($worker) 
  14. { 
  15.     // 开启一个内部端口,方便内部系统推送数据,Text协议格式 文本+换行符 
  16.     $inner_text_worker = new Worker('text://0.0.0.0:5678'); 
  17.     $inner_text_worker->onMessage = function($connection, $buffer) 
  18.     { 
  19.         // $data数组格式,里面有uid,表示向那个uid的页面推送数据 
  20.         $data = json_decode($buffer, true); 
  21.         $uid = $data['uid']; 
  22.         // 通过workerman,向uid的页面推送数据 
  23.         $ret = sendMessageByUid($uid, $buffer); 
  24.         // 返回推送结果 
  25.         $connection->send($ret ? 'ok' : 'fail'); 
  26.     }; 
  27.     // $connection->send('你好,你连接我了'); 
  28.     // ## 执行监听 ## 
  29.     $inner_text_worker->listen(); 
  30. }; 
  31. // 新增加一个属性,用来保存uid到connection的映射 
  32. $worker->uidConnections = array(); 
  33. // 当有客户端发来消息时执行的回调函数 
  34. $worker->onMessage = function($connection, $data) 
  35. { 
  36.     $data=json_decode($data,true); 
  37.     $connection->send('99897'); 
  38.     global $worker; 
  39.     // 判断当前客户端是否已经验证,既是否设置了uid 
  40.     if(!isset($connection->uid)) 
  41.     { 
  42.         // 没验证的话把第一个包当做uid(这里为了方便演示,没做真正的验证) 
  43.         $connection->uid = $data['id']; 
  44.         /* 保存uid到connection的映射,这样可以方便的通过uid查找connection, 
  45.          * 实现针对特定uid推送数据 
  46.          */ 
  47.         $worker->uidConnections[$connection->uid] = $connection; 
  48.         $connection->send('9980'.$data['msg']); 
  49.         return; 
  50.     }else{ 
  51.          $connection->send('998123'); 
  52.     } 
  53. }; 
  54. // 当有客户端连接断开时 
  55. $worker->onClose = function($connection) 
  56. { 
  57.     global $worker; 
  58.     if(isset($connection->uid)) 
  59.     { 
  60.         // 连接断开时删除映射 
  61.         unset($worker->uidConnections[$connection->uid]); 
  62.     } 
  63. }; 
  64. // 向所有验证的用户推送数据 
  65. function broadcast($message) 
  66. { 
  67.     global $worker; 
  68.     foreach($worker->uidConnections as $connection) 
  69.     { 
  70.         $connection->send($message); 
  71.     } 
  72. } 
  73. // 针对uid推送数据 
  74. function sendMessageByUid($uid, $message) 
  75. { 
  76.     global $worker; 
  77.     if(isset($worker->uidConnections[$uid])) 
  78.     { 
  79.         $connection = $worker->uidConnections[$uid]; 
  80.         $connection->send($message); 
  81.         return true; 
  82.     } 
  83.     return false; 
  84. } 

运行所有的worker

Worker::runAll();

启动后端服务 php push.php start -d

前端接收推送的js代码

  1. <!DOCTYPE html> 
  2. <html lang="en"> 
  3. <head> 
  4.     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
  5.     <title>Title</title> 
  6. </head> 
  7. <body> 
  8. <script> 
  9.     var ws = new WebSocket('ws://118.**.**.207:1234'); 
  10.     ws.onopen = function(){ 
  11.         var uid = 'uid1'; 
  12.         ws.send(uid); 
  13.         console.log("给服务端发送一个字符串:"+uid); 
  14.     }; 
  15.     ws.onmessage = function(e){ 
  16.         // alert(e.data); 
  17.         console.log("收到服务端的消息:" + e.data); 
  18.     }; 
  19. </script> 
  20. </body> 
  21. </html> 

后端推送消息的代码

  1. // 建立socket连接到内部推送端口 
  2. $client = stream_socket_client('tcp://127.0.0.1:5678', $errno, $errmsg, 1); 
  3. // 推送的数据,包含uid字段,表示是给这个uid推送 
  4. $data = array('uid'=>'uid1', 'percent'=>'88%'); 
  5. // 发送数据,注意5678端口是Text协议的端口,Text协议需要在数据末尾加上换行符 
  6. fwrite($client, json_encode($data)."\n"); 
  7. // 读取推送结果 
  8. echo fread($client, 8192); 

后端推送消息的代码和push.php监听同一个端口

push.php和前端监听同一个websocket端口

通过后端推送消息的代码向push.php推送数据,push.php接受到数据后通过处理 利用websocket往前端推送数据

Tags: Workerman

分享到: