首先看CRMEB驻留内存的bat
start cmd /c php think workerman start chat
start cmd /c php think workerman start admin
start cmd /c php think timer start
php think workerman start channel
程序启动于think文件
#!/usr/bin/env php
<?php
namespace think;
// 加载基础文件
require __DIR__ . '/vendor/autoload.php';
// 应用初始化
(new App())->console->run();
CRMEB基于ThinkPHP,ThinkPHP按composer的模式整理了程序的启动过程,有空的小白应该可能去认真研读一下autoload.php内部的相关代码,这样对学习进程会很有帮助
通过命名空间think找到vendor/topthink/framework/src/think/Console.php文件,Console类中,__construct函数通过loadCommands函数加载了配置
/**
* 加载指令
* @access protected
*/
protected function loadCommands(): void
{
$commands = $this->app->config->get('console.commands', []);
$commands = array_merge($this->defaultCommands, $commands);
$this->addCommands($commands);
}
注意到$this->app->config->get从console.commands读配置,那配置文件在哪里呢?这就需要回过头来研读一下App.php这个文件了(文章所限,省略掉不重要的代码)
public function initialize()
{
......
// 加载全局初始化文件
$this->load();
......
}
protected function load(): void
{
......
foreach ($files as $file) {
$this->config->load($file, pathinfo($file, PATHINFO_FILENAME));
}
.....
}
通过代码得知,程序加载时,即从/config目录下,把所有配置文件都加载进来,console.commands配置项即是console.php配置文件中的commands配置项。那我们就可以知道,聊天相关的对象是在\crmeb\command\Workerman这个类中。
下面来看一下Workerman类的execute方法,workerServer属性与chatWorkerServer长连接对象都是Worker对象实例,这个大家要学一下Workerman的资料了:
protected function execute(Input $input, Output $output)
{
$server = $this->init($input, $output);
Worker::$pidFile = app()->getRootPath().'workerman.pid';
if(!$server || $server == 'admin'){
var_dump('admin');
//创建 admin 长连接服务
$this->workerServer = new Worker($this->config['admin']['protocol'] . '://' . $this->config['admin']['ip'] . ':' . $this->config['admin']['port']);
$this->workerServer->count = $this->config['admin']['serverCount'];
}
if(!$server || $server == 'chat') {
var_dump('chat');
//创建 h5 chat 长连接服务
$this->chatWorkerServer = new Worker($this->config['chat']['protocol'] . '://' . $this->config['chat']['ip'] . ':' . $this->config['chat']['port']);
$this->chatWorkerServer->count = $this->config['chat']['serverCount'];
}
if(!$server || $server == 'channel') {
var_dump('channel');
//创建内部通讯服务
$this->channelServer = new Server($this->config['channel']['ip'], $this->config['channel']['port']);
}
$this->bindHandle();
try {
Worker::runAll();
} catch (\Exception $e) {
$output->warning($e->getMessage());
}
}
注意:配置是从$this->config[‘admin’][‘protocol’],查找配置文件的目录workerman.php配置文件包含了这些配置项,配置项是通过config函数来读的,config函数是在/vendor/topthink/framework/src/helper.php文件中,也是用Config类读取配置的
从bindHandle方法中,得知ChatService是接收聊天对话的业务类
protected function bindHandle()
{
if(!is_null($this->workerServer)){
$server = new WorkermanService($this->workerServer, $this->channelServer);
// 连接时回调
$this->workerServer->onConnect = [$server, 'onConnect'];
// 收到客户端信息时回调
$this->workerServer->onMessage = [$server, 'onMessage'];
// 进程启动后的回调
$this->workerServer->onWorkerStart = [$server, 'onWorkerStart'];
// 断开时触发的回调
$this->workerServer->onClose = [$server, 'onClose'];
}
if(!is_null($this->chatWorkerServer)) {
$chatServer = new ChatService($this->chatWorkerServer, $this->channelServer);
$this->chatWorkerServer->onConnect = [$chatServer, 'onConnect'];
$this->chatWorkerServer->onMessage = [$chatServer, 'onMessage'];
$this->chatWorkerServer->onWorkerStart = [$chatServer, 'onWorkerStart'];
$this->chatWorkerServer->onClose = [$chatServer, 'onClose'];
}
}
/crmeb/service/workerman/chat/ChatService.php文件中,ChatService类用ChatHandle来进行业务相关操作,对于需要进行二次开发的小白来说,可以修改ChatHandle来完善业务功能,我感觉也可以通过传入的参数调用不同业务对象的功能,这样才能实现灵活扩展的目的。
好了,就聊到这