- 基础文档:Workerman · ThinkPHP5.0完全开发手册 · 看云
- 在线测试地址:EasySwoole-WebSocket在线测试工具 或者postman eolink等api工具等 都可以
一、thinkphp5 安装扩展包 composer require topthink/think-worker
遇到报错:不能安装,参考:tp5 workerman安装不上解决方法 - 知乎
thinkphp5.0 直接执行:composer require topthink/think-worker=1.0.* 即可成功 thinkPHP 5.1以上版本可以执行composer require topthink/think-worker=2.0.* 用最新版
二、在你项目根目录下 新建 server.php文件 (注:我的运行文件是放在public下)
#!/usr/bin/env php
<?php
define('APP_PATH', __DIR__ . '/application/');
define('BIND_MODULE','worker/Worker');
// 加载框架引导文件
require __DIR__ . '/../thinkphp/start.php';
三、新建Worker.php 可直接用命令创建 php think make:controller worker/Worker即可,将里面的内容替换如下所示:
<?php
namespace app\worker\controller;
use think\Controller;
use think\Request;
use think\worker\Server;
use think\Cache;
use Workerman\Worker as TcpWorker;
class Worker extends Server
{
protected $socket = 'websocket://0.0.0.0:2346';//此处可创建TCP服务或者websocket服务 端口需要在你的云服务器安全组放行 端口任意 但与其他使用端口不能重复
//protected $socket = 'tcp://0.0.0.0:2346';
protected $processes = 1;
protected $uidConnections = array();
static $count = 0;
protected $HEARTBEAT_TIME = '60';
/**
* 收到信息
* @param $connection
* @param $data
*/
public function onMessage($connection, $data)
{
//$data为客户端发送过的消息 接收到以后可进行你的逻辑操作
$retdata=json_decode($data,true);
$uid=$connection->id;
$message= 'Received successfully 收到来自_id='.$uid.'_客户端的消息:'.$data."\r\n";
if(isset($this->uidConnections[$uid]))
{
$connection = $this->uidConnections[$uid];
}
$connection->send($message);
}
/**
* 当连接建立时触发的回调函数
* @param $connection
*/
public function onConnect($connection)
{
$this->uidConnections[$connection->id] = $connection;
$connection->send('你连接了我='.$connection->id);
}
// 针对uid推送数据
public function sendMessageByUid($uid, $message)
{
if(isset($this->uidConnections[$uid]))
{
$connection = $this->uidConnections[$uid];
$connection->send($message);
return true;
}
return false;
}
/**
* 当连接断开时触发的回调函数
* @param $connection
*/
public function onClose($connection)
{
if(isset($connection->uid))
{
// 连接断开时删除映射
unset($this->uidConnections[$connection->uid]);
}
}
/**
* 当客户端的连接上发生错误时触发
* @param $connection
* @param $code
* @param $msg
*/
public function onError($connection, $code, $msg)
{
echo "error $code $msg\n";
}
/**
* 每个进程启动
* @param $worker
*/
public function onWorkerStart($worker)
{
// 开启一个内部端口,方便内部系统推送数据(配置下列方法可实现在服务端通过api向客户端发送信息指令),Text协议格式 文本+换行符
$inner_text_worker = new TcpWorker('text://0.0.0.0:5678');
$inner_text_worker->onMessage = function($connection, $buffer)
{
// $data数组格式,里面有uid,表示向那个uid的页面推送数据
$data = json_decode($buffer, true);
$uid = $data['uid'];
// 通过workerman,向uid的页面推送数据
$ret = $this->sendMessageByUid($uid,$buffer);
// 返回推送结果
$connection->send($ret ? 'ok' : 'fail');
};
// ## 执行监听 ##
$inner_text_worker->listen();
//定时器 如果上次发送信息后在间隔时间内没有新的消息则关闭连接
// Timer::add(10, function()use($worker){
// $time_now = time();
// foreach($worker->connections as $connection) {
// // 有可能该connection还没收到过消息,则lastMessageTime设置为当前时间
// if (empty($connection->lastMessageTime)) {
// $connection->lastMessageTime = $time_now;
// continue;
// }
// // $diff_time = $time_now - $connection->lastMessageTime;
// // $msg = '距离上次通话已经过去'.$diff_time.'秒';
// // $connection->send($msg);
// // 上次通讯时间间隔大于心跳间隔,则认为客户端已经下线,关闭连接
// if ($time_now - $connection->lastMessageTime > $this->HEARTBEAT_TIME) {
// $connection->close();
// }
// }
// });
}
}
// 针对uid推送数据
public function sendMessageByUid($uid, $message)
{
if(isset($this->uidConnections[$uid]))
{
$connection = $this->uidConnections[$uid];
$connection->send($message);
return true;
}
return false;
}
}
四、执行启动服务命令 php server.php start 测试时可不用守护进程开启
测试通以后可使用 php server.php start -d 守护进程开启
php server.php stop 关闭服务 切记在修改运行代码之后要重启服务
遇到禁用函数就去对应的PHP里面把禁用函数删除 (此命令可以放到Supervisor的守护进程里面去),并且查看端口是否运行,宝塔里面也要放行对应的端口 2346
五、在服务端 向客户端主动发送消息
public function sendToClient(){
// 建立socket连接到内部推送端口
$client = stream_socket_client('tcp://127.0.0.1:5678', $errno, $errmsg, 1);//此端口号必须与进程启动 同配置的端口号一致 内部通讯
// 推送的数据,包含uid字段,表示是给这个uid推送
$data = array('uid'=>'uid1', 'percent'=>'88%');
// 发送数据,注意5678端口是Text协议的端口,Text协议需要在数据末尾加上换行符
fwrite($client, json_encode($data)."\n");
// 读取推送结果
echo fread($client, 8192);
}
参考:
以下为测试方法
一 在运行目录 命令行执行 php server.php start
二 在测试工具 创建Tcp链接或者ws链接
三 此时命令行会收到测试工具发来的数据
四 在服务端你需要的地方 调用sendToClient方法 此方法可写成公共方法 调用发送信息后 在命令行就可以收到服务端主动发送的消息