aardio里开发websocket服务端和客户端很简单,前几天搞过一个聊天室玩玩。
php里也想搞个websocket服务器,因为php和linux更配。但有时候又想用windows服务器,Workerman就成了不二选择。
TP5里也介绍了Workerman的库,具体看文档 https://www.kancloud.cn/manual/thinkphp5_1/354134
启动到tp环境后php命令行启动 php think worker:server ,linux也支持支持reload|restart|stop|status 操作 如php think worker:server reload。
默认在配置文件里有个worker_server.php配置文件。但把事件处理什么的都写在配置文件里好像不是我的风格。
<?php
use think\facade\Env;
// +----------------------------------------------------------------------
// | Workerman设置 仅对 php think worker:server 指令有效
// +----------------------------------------------------------------------
return [
// 扩展自身需要的配置
'protocol' => 'websocket', // 协议 支持 tcp udp unix http websocket text
'host' => '0.0.0.0', // 监听地址
'port' => 8876, // 监听端口
'socket' => '', // 完整监听地址
'context' => [], // socket 上下文选项
'worker_class' => '', // 自定义Workerman服务类名 支持数组定义多个服务
// 支持workerman的所有配置参数
'name' => 'thinkphp',
'count' => 4,
'daemonize' => false,
'pidFile' => Env::get('runtime_path') . 'worker.pid',
// 支持事件回调
// onWorkerStart
'onWorkerStart' => function ($worker) {
},
// onWorkerReload
'onWorkerReload' => function ($worker) {
},
// onConnect
'onConnect' => function ($connection) {
},
// onMessage
'onMessage' => function ($connection, $data) {
$connection->send('你好,啊购');
},
// onClose
'onClose' => function ($connection) {
},
// onError
'onError' => function ($connection, $code, $msg) {
echo "error [ $code ] $msg\n";
},
];
按说明单独配置个库吧,不过配置库后好像很多配置文件都就失效了
'worker_class' => 'app\stock\Worker', // 自定义Workerman服务类名 支持数组定义多个服务
另一份文档 http://doc.workerman.net/worker/on-connect.html
TP的文档里有用单独服务类的例子,可惜不完全,自己试了下,和以前写的那个aardio网络聊天的进行通讯,可以。那就上上来吧。反正自己的业务逻辑不是这个。
<?php
/**
*
* @author 劲松_楚鸟
* @date 2021-03-28 14:18:00
* @workes websocket服务器组件,用来试试和以前aardio写的聊天页面连
*/
namespace app\stock;
use think\worker\Server;
use think\facade\App;
class Worker extends Server
{
protected $socket = 'websocket://0.0.0.0:8876';
// 扩展自身需要的配置
protected $option =[
// 支持workerman的所有配置参数
'name' => '聊天测试', //进程名称,方便识别
'count' => 4
];
/**
* 看文本调试信息
* $data-变量
* PHP_EOL-根据系统环境确定换行(换行)
* FILE_APPEND - 追加参数
**/
private function log($data){
$log_filename = App::getRuntimePath() . 'log'. DIRECTORY_SEPARATOR . date('Ym') . DIRECTORY_SEPARATOR .date('d'). ".log";
if(is_array($data)){
$text='[result]='.var_export($data,true).';';
}else{
$text = $data;
}
$contents = '['.date('Y-m-d H:i:s',time()).']'.PHP_EOL.$text;
$res = file_put_contents($log_filename,$contents.PHP_EOL, FILE_APPEND);
}
//初始群发信息
protected function initcopy(){
$tab = $this->globalEvent;
//第一次,全转发
foreach($tab as $k=>$v)
{
$this->worker->connections[$k]->send(\json_encode($v));
}
}
//客户端连接过来初始事件,数据存全局
protected function onopeninit($connection){
$newtab = [];
$newtab['ip'] = $connection->getRemoteIp();
$newtab['trme'] = \date("Y-m-d H:m:s",time()); //登录时间
$clent = $connection->id; //连接进程标志
$this->globalEvent[$clent] = $newtab ; //用来存储所有标志,嘻哈表,取快
}
//客户端连接过来初始事件,没有的就从表里删除
protected function rm_hsocket($id){
unset($this->globalEvent[$id]);
}
//启动回调函数
public function onWorkerStart($worker)
{
echo '启动啦';
}
//客户端与Workerman建立连接时(TCP三次握手完成后)触发的回调函数
public function onConnect($connection)
{
$this->onopeninit($connection);
}
//当客户端通过连接发来数据时(Workerman收到数据时)触发的回调函数
public function onMessage($connection,$data)
{
try {
$data = json_decode($data,true);
} catch (\Throwable $th) {
$this->log($th) ;
}
$this->log($data) ;
if($data){
if(isset($data['status'])){
switch ($data['status']) { //这里通过status判断不同的状态进行不同的事件
case 'init': //初始,第一次发信息
if(!isset($data['name'])) return $this->rm_hsocket($connection->id) ; //全局移除那个指针
$tab = $this->globalEvent; //全局静态
$this->log($tab) ;
$tab[$connection->id]['name']=$data['name']; //标志
$this->initcopy($tab); //第一次连接后发送初始化界面信息
break;
default:
# code...
break;
}
}
}
}
//设置Worker收到reload信号后执行的回调。用的少
public function onWorkerReload($worker)
{
}
//当客户端连接与Workerman断开时触发的回调函数
public function onClose($connection)
{
return $this->rm_hsocket($connection->id) ; //全局移除那个指针
}
//报错时回调函数
public function onError($connection, $code, $msg)
{
echo "error [ $code ] $msg\n";
}
}
没写详细和完全,主要是测试的,我的业务逻辑不搞这。
以前aardio写的聊天测试,可以和这个配合看:http://blog.jvbaopeng.com/blog/156.html
最后噗嗤噗嗤写完了,然后小程序上好像不能用,一链接就断,wss的
加上这个配置就好
// 扩展自身需要的配置
protected $option =[
// 支持workerman的所有配置参数
'name' => '聚宝盆记账易', //进程名称,方便识别
'count' => 4,
'transport' => 'ssl'
];
// 证书最好是申请的证书
protected $context = array(
// 更多ssl选项请参考手册 http://php.net/manual/zh/context.ssl.php
'ssl' => array(
// 请使用绝对路径
'local_cert' => './zhen/my.pem', // 也可以是crt文件
'local_pk' => './zhen/my.key',
'verify_peer' => false,
)
);