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

四、执行 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.     // 开启一个内部端口,方便内部系统推送数据,Text协议格式 文本+换行符 
  15.     $inner_text_worker = new Worker('text://0.0.0.0:5678'); 
  16.     $inner_text_worker->onMessage = function($connection$buffer
  17.     { 
  18.         // $data数组格式,里面有uid,表示向那个uid的页面推送数据 
  19.         $data = json_decode($buffer, true); 
  20.         $uid = $data['uid']; 
  21.         // 通过workerman,向uid的页面推送数据 
  22.         $ret = sendMessageByUid($uid$buffer); 
  23.         // 返回推送结果 
  24.         $connection->send($ret ? 'ok' : 'fail'); 
  25.     }; 
  26.     // $connection->send('你好,你连接我了'); 
  27.     // ## 执行监听 ## 
  28.     $inner_text_worker->listen(); 
  29. }; 
  30. // 新增加一个属性,用来保存uid到connection的映射 
  31. $worker->uidConnections = array(); 
  32. // 当有客户端发来消息时执行的回调函数 
  33. $worker->onMessage = function($connection$data
  34.     $data=json_decode($data,true); 
  35.     $connection->send('99897'); 
  36.     global $worker
  37.     // 判断当前客户端是否已经验证,既是否设置了uid 
  38.     if(!isset($connection->uid)) 
  39.     { 
  40.         // 没验证的话把第一个包当做uid(这里为了方便演示,没做真正的验证) 
  41.         $connection->uid = $data['id']; 
  42.         /* 保存uid到connection的映射,这样可以方便的通过uid查找connection, 
  43.          * 实现针对特定uid推送数据 
  44.          */ 
  45.         $worker->uidConnections[$connection->uid] = $connection
  46.         $connection->send('9980'.$data['msg']); 
  47.         return
  48.     }else
  49.          $connection->send('998123'); 
  50.     } 
  51. }; 
  52. // 当有客户端连接断开时 
  53. $worker->onClose = function($connection
  54.     global $worker
  55.     if(isset($connection->uid)) 
  56.     { 
  57.         // 连接断开时删除映射 
  58.         unset($worker->uidConnections[$connection->uid]); 
  59.     } 
  60. }; 
  61. // 向所有验证的用户推送数据 
  62. function broadcast($message
  63.     global $worker
  64.     foreach($worker->uidConnections as $connection
  65.     { 
  66.         $connection->send($message); 
  67.     } 
  68. // 针对uid推送数据 
  69. function sendMessageByUid($uid$message
  70.     global $worker
  71.     if(isset($worker->uidConnections[$uid])) 
  72.     { 
  73.         $connection = $worker->uidConnections[$uid]; 
  74.         $connection->send($message); 
  75.         return true; 
  76.     } 
  77.     return false; 

运行所有的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

分享到: