feat(websocket): 添加日志封装函数并优化服务器启动输出
添加ws_log系列函数封装日志记录,统一WebSocket服务器日志格式 使用ws_echo替换原有echo输出,同时记录日志和控制台显示 优化服务器启动流程,增加配置信息输出和状态记录
This commit is contained in:
@@ -10,6 +10,89 @@ error_reporting(E_ALL);
|
|||||||
|
|
||||||
require __DIR__ . '/vendor/autoload.php';
|
require __DIR__ . '/vendor/autoload.php';
|
||||||
|
|
||||||
|
// 引入应用公共文件,包含log_write函数
|
||||||
|
require __DIR__ . '/app/common.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WebSocket服务器日志封装函数
|
||||||
|
* 简化log_write函数的调用,自动添加WebSocket服务器前缀
|
||||||
|
*
|
||||||
|
* @param string $message 日志内容
|
||||||
|
* @param string $level 日志级别:info, warning, error
|
||||||
|
* @param int $callerDep 调用栈深度,默认1
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function ws_log(string $message, string $level = 'info', int $callerDep = 1): void
|
||||||
|
{
|
||||||
|
log_write($message, $level, 'websocket-server.log', $callerDep + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WebSocket服务器错误日志封装函数
|
||||||
|
* 简化错误日志的记录,自动添加WebSocket服务器前缀
|
||||||
|
*
|
||||||
|
* @param string $message 错误信息
|
||||||
|
* @param int $callerDep 调用栈深度,默认1
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function ws_error(string $message, int $callerDep = 1): void
|
||||||
|
{
|
||||||
|
log_write($message, 'error', 'websocket-server.log', $callerDep + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WebSocket服务器警告日志封装函数
|
||||||
|
* 简化警告日志的记录,自动添加WebSocket服务器前缀
|
||||||
|
*
|
||||||
|
* @param string $message 警告信息
|
||||||
|
* @param int $callerDep 调用栈深度,默认1
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function ws_warning(string $message, int $callerDep = 1): void
|
||||||
|
{
|
||||||
|
log_write($message, 'warning', 'websocket-server.log', $callerDep + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WebSocket服务器信息日志封装函数
|
||||||
|
* 简化信息日志的记录,自动添加WebSocket服务器前缀
|
||||||
|
*
|
||||||
|
* @param string $message 信息内容
|
||||||
|
* @param int $callerDep 调用栈深度,默认1
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function ws_info(string $message, int $callerDep = 1): void
|
||||||
|
{
|
||||||
|
log_write($message, 'info', 'websocket-server.log', $callerDep + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WebSocket服务器输出封装函数
|
||||||
|
* 同时处理日志记录和控制台输出,使代码更简洁
|
||||||
|
*
|
||||||
|
* @param string $message 输出内容
|
||||||
|
* @param string $level 日志级别:info, warning, error
|
||||||
|
* @param int $callerDep 调用栈深度,默认1
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function ws_echo(string $message, string $level = 'info', int $callerDep = 1): void
|
||||||
|
{
|
||||||
|
// 调用相应的日志函数
|
||||||
|
switch ($level) {
|
||||||
|
case 'error':
|
||||||
|
ws_error($message, $callerDep + 1);
|
||||||
|
break;
|
||||||
|
case 'warning':
|
||||||
|
ws_warning($message, $callerDep + 1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ws_info($message, $callerDep + 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// 输出到控制台
|
||||||
|
echo $message . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
// 初始化ThinkPHP应用环境,加载配置和环境变量,主要用于数据库连接和其他配置
|
// 初始化ThinkPHP应用环境,加载配置和环境变量,主要用于数据库连接和其他配置
|
||||||
use think\App;
|
use think\App;
|
||||||
|
|
||||||
@@ -77,8 +160,13 @@ if ($httpHost === '') {
|
|||||||
$port = getenv('WS_PORT') ?: 8080; // WebSocket服务器端口
|
$port = getenv('WS_PORT') ?: 8080; // WebSocket服务器端口
|
||||||
$address = '0.0.0.0'; // 监听所有网络接口
|
$address = '0.0.0.0'; // 监听所有网络接口
|
||||||
|
|
||||||
|
// 记录服务器启动信息
|
||||||
|
ws_echo("[WebSocket服务器] 正在启动...");
|
||||||
|
ws_echo("[WebSocket服务器] 配置信息: HTTP_HOST={$httpHost}, PORT={$port}, ADDRESS={$address}");
|
||||||
|
|
||||||
// 创建WebSocket服务器应用 - 参数顺序:httpHost, port, address
|
// 创建WebSocket服务器应用 - 参数顺序:httpHost, port, address
|
||||||
$ratchetApp = new RatchetApp($httpHost, $port, $address);
|
$ratchetApp = new RatchetApp($httpHost, $port, $address);
|
||||||
|
ws_echo("[WebSocket服务器] 应用创建成功");
|
||||||
|
|
||||||
// 获取所有addon(与InitAddon.php逻辑保持一致)
|
// 获取所有addon(与InitAddon.php逻辑保持一致)
|
||||||
// 1. 从数据库获取插件列表
|
// 1. 从数据库获取插件列表
|
||||||
@@ -97,10 +185,10 @@ try {
|
|||||||
$cachedAddons = $cache->get($cacheKey);
|
$cachedAddons = $cache->get($cacheKey);
|
||||||
|
|
||||||
if ($cachedAddons !== null && !empty($cachedAddons)) {
|
if ($cachedAddons !== null && !empty($cachedAddons)) {
|
||||||
echo "[WebSocket服务器] 从缓存获取插件列表\n";
|
ws_echo("[WebSocket服务器] 从缓存获取插件列表");
|
||||||
$current_addons = $cachedAddons;
|
$current_addons = $cachedAddons;
|
||||||
} else {
|
} else {
|
||||||
echo "[WebSocket服务器] 从数据库获取插件列表\n";
|
ws_echo("[WebSocket服务器] 从数据库获取插件列表");
|
||||||
|
|
||||||
// 尝试获取数据库连接并确保连接有效
|
// 尝试获取数据库连接并确保连接有效
|
||||||
try {
|
try {
|
||||||
@@ -111,10 +199,10 @@ try {
|
|||||||
|
|
||||||
// 将结果存入缓存
|
// 将结果存入缓存
|
||||||
$cache->set($cacheKey, $current_addons, $cacheExpire);
|
$cache->set($cacheKey, $current_addons, $cacheExpire);
|
||||||
echo "[WebSocket服务器] 插件列表已缓存(有效期: {$cacheExpire}秒)\n";
|
ws_echo("[WebSocket服务器] 插件列表已缓存(有效期: {$cacheExpire}秒)");
|
||||||
} catch (\Exception $dbEx) {
|
} catch (\Exception $dbEx) {
|
||||||
echo "[WebSocket服务器] 数据库操作失败: {$dbEx->getMessage()}\n";
|
ws_echo("[WebSocket服务器] 数据库操作失败: {$dbEx->getMessage()}", 'error');
|
||||||
echo "[WebSocket服务器] 尝试重新初始化数据库连接...\n";
|
ws_echo("[WebSocket服务器] 尝试重新初始化数据库连接...");
|
||||||
|
|
||||||
// 尝试重新初始化应用和数据库连接
|
// 尝试重新初始化应用和数据库连接
|
||||||
try {
|
try {
|
||||||
@@ -129,10 +217,10 @@ try {
|
|||||||
|
|
||||||
// 将结果存入缓存
|
// 将结果存入缓存
|
||||||
$cache->set($cacheKey, $current_addons, $cacheExpire);
|
$cache->set($cacheKey, $current_addons, $cacheExpire);
|
||||||
echo "[WebSocket服务器] 重新连接数据库成功,插件列表已缓存\n";
|
ws_echo("[WebSocket服务器] 重新连接数据库成功,插件列表已缓存");
|
||||||
} catch (\Exception $retryEx) {
|
} catch (\Exception $retryEx) {
|
||||||
echo "[WebSocket服务器] 重新连接数据库失败: {$retryEx->getMessage()}\n";
|
ws_echo("[WebSocket服务器] 重新连接数据库失败: {$retryEx->getMessage()}", 'error');
|
||||||
echo "[WebSocket服务器] 回退到直接扫描目录获取插件列表\n";
|
ws_echo("[WebSocket服务器] 回退到直接扫描目录获取插件列表");
|
||||||
|
|
||||||
// 回退到直接扫描目录
|
// 回退到直接扫描目录
|
||||||
$addonNames = [];
|
$addonNames = [];
|
||||||
@@ -183,25 +271,25 @@ try {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
echo "[WebSocket服务器] 从数据库获取的插件列表: " . implode(', ', $current_addon_names) . "\n";
|
ws_echo("[WebSocket服务器] 从数据库获取的插件列表: " . implode(', ', $current_addon_names));
|
||||||
echo "[WebSocket服务器] 已启用的插件: " . implode(', ', $enabled_addons) . "\n";
|
ws_echo("[WebSocket服务器] 已启用的插件: " . implode(', ', $enabled_addons));
|
||||||
echo "[WebSocket服务器] 目录中存在的插件: " . implode(', ', $dir_addon_names) . "\n";
|
ws_echo("[WebSocket服务器] 目录中存在的插件: " . implode(', ', $dir_addon_names));
|
||||||
|
|
||||||
// 5. 比较数据库和目录插件列表的差异
|
// 5. 比较数据库和目录插件列表的差异
|
||||||
$db_only_addons = array_diff($db_addon_names, $dir_addon_names);
|
$db_only_addons = array_diff($db_addon_names, $dir_addon_names);
|
||||||
$dir_only_addons = array_diff($dir_addon_names, $db_addon_names);
|
$dir_only_addons = array_diff($dir_addon_names, $db_addon_names);
|
||||||
|
|
||||||
if (!empty($db_only_addons)) {
|
if (!empty($db_only_addons)) {
|
||||||
echo "[WebSocket服务器] 数据库中存在但目录中不存在的插件: " . implode(', ', $db_only_addons) . "\n";
|
ws_echo("[WebSocket服务器] 数据库中存在但目录中不存在的插件: " . implode(', ', $db_only_addons));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($dir_only_addons)) {
|
if (!empty($dir_only_addons)) {
|
||||||
echo "[WebSocket服务器] 目录中存在但数据库中不存在的插件: " . implode(', ', $dir_only_addons) . "\n";
|
ws_echo("[WebSocket服务器] 目录中存在但数据库中不存在的插件: " . implode(', ', $dir_only_addons));
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
echo "[WebSocket服务器] 获取插件列表失败: " . $e->getMessage() . "\n";
|
ws_echo("[WebSocket服务器] 获取插件列表失败: " . $e->getMessage(), 'error');
|
||||||
echo "[WebSocket服务器] 回退到直接扫描目录获取插件列表\n";
|
ws_echo("[WebSocket服务器] 回退到直接扫描目录获取插件列表");
|
||||||
|
|
||||||
// 回退到直接扫描目录
|
// 回退到直接扫描目录
|
||||||
$addonNames = [];
|
$addonNames = [];
|
||||||
@@ -229,14 +317,14 @@ $missingDirAddons = [];
|
|||||||
foreach ($current_addon_names as $addonName) {
|
foreach ($current_addon_names as $addonName) {
|
||||||
// 检查插件是否已启用
|
// 检查插件是否已启用
|
||||||
if (!in_array($addonName, $enabled_addons)) {
|
if (!in_array($addonName, $enabled_addons)) {
|
||||||
echo "[{$addonName}] 插件未启用,跳过WebSocket控制器注册\n";
|
ws_echo("[{$addonName}] 插件未启用,跳过WebSocket控制器注册");
|
||||||
$disabledAddons[] = $addonName;
|
$disabledAddons[] = $addonName;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查插件目录是否存在
|
// 检查插件目录是否存在
|
||||||
if (!is_dir($addonDir . '/' . $addonName)) {
|
if (!is_dir($addonDir . '/' . $addonName)) {
|
||||||
echo "[{$addonName}] 插件目录不存在,跳过WebSocket控制器注册\n";
|
ws_echo("[{$addonName}] 插件目录不存在,跳过WebSocket控制器注册");
|
||||||
$missingDirAddons[] = $addonName;
|
$missingDirAddons[] = $addonName;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -250,14 +338,14 @@ foreach ($current_addon_names as $addonName) {
|
|||||||
$path = '/ws/' . $addonName;
|
$path = '/ws/' . $addonName;
|
||||||
// 允许任意 Origin,并且不限制 Host(支持通过任意 IP/域名访问)
|
// 允许任意 Origin,并且不限制 Host(支持通过任意 IP/域名访问)
|
||||||
$ratchetApp->route($path, new $webSocketClass(), array('*'), '');
|
$ratchetApp->route($path, new $webSocketClass(), array('*'), '');
|
||||||
echo "已注册WebSocket控制器:{$webSocketClass} 到路径 {$path}\n";
|
ws_echo("已注册WebSocket控制器:{$webSocketClass} 到路径 {$path}");
|
||||||
$registeredAddons[] = $addonName;
|
$registeredAddons[] = $addonName;
|
||||||
} else {
|
} else {
|
||||||
echo "[{$addonName}] WebSocket控制器不存在 ({$webSocketClass})\n";
|
ws_echo("[{$addonName}] WebSocket控制器不存在 ({$webSocketClass})");
|
||||||
$unregisteredAddons[] = $addonName;
|
$unregisteredAddons[] = $addonName;
|
||||||
}
|
}
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
echo "[{$addonName}] 检查WebSocket控制器时出错:{$e->getMessage()}\n";
|
ws_echo("[{$addonName}] 检查WebSocket控制器时出错:{$e->getMessage()}", 'error');
|
||||||
$unregisteredAddons[] = $addonName;
|
$unregisteredAddons[] = $addonName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -275,7 +363,7 @@ class DefaultWebSocketController implements MessageComponentInterface
|
|||||||
public function onOpen(ConnectionInterface $conn)
|
public function onOpen(ConnectionInterface $conn)
|
||||||
{
|
{
|
||||||
$this->clients->attach($conn);
|
$this->clients->attach($conn);
|
||||||
echo "[默认路径] New connection! ({$conn->resourceId})\n";
|
ws_echo("[默认路径] New connection! ({$conn->resourceId})");
|
||||||
$conn->send(json_encode([
|
$conn->send(json_encode([
|
||||||
'type' => 'welcome',
|
'type' => 'welcome',
|
||||||
'message' => '欢迎连接到默认WebSocket测试路径',
|
'message' => '欢迎连接到默认WebSocket测试路径',
|
||||||
@@ -285,7 +373,7 @@ class DefaultWebSocketController implements MessageComponentInterface
|
|||||||
|
|
||||||
public function onMessage(ConnectionInterface $conn, $msg)
|
public function onMessage(ConnectionInterface $conn, $msg)
|
||||||
{
|
{
|
||||||
echo "[默认路径] Received message from {$conn->resourceId}: $msg\n";
|
ws_echo("[默认路径] Received message from {$conn->resourceId}: $msg");
|
||||||
try {
|
try {
|
||||||
$data = json_decode($msg, true);
|
$data = json_decode($msg, true);
|
||||||
if (isset($data['action']) && $data['action'] === 'ping') {
|
if (isset($data['action']) && $data['action'] === 'ping') {
|
||||||
@@ -298,6 +386,7 @@ class DefaultWebSocketController implements MessageComponentInterface
|
|||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
|
ws_echo("[默认路径] 解析消息失败: {$e->getMessage()}", 'error');
|
||||||
$conn->send(json_encode(['type' => 'error', 'message' => '解析消息失败: ' . $e->getMessage()]));
|
$conn->send(json_encode(['type' => 'error', 'message' => '解析消息失败: ' . $e->getMessage()]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -305,12 +394,12 @@ class DefaultWebSocketController implements MessageComponentInterface
|
|||||||
public function onClose(ConnectionInterface $conn)
|
public function onClose(ConnectionInterface $conn)
|
||||||
{
|
{
|
||||||
$this->clients->detach($conn);
|
$this->clients->detach($conn);
|
||||||
echo "[默认路径] Connection {$conn->resourceId} has disconnected\n";
|
ws_echo("[默认路径] Connection {$conn->resourceId} has disconnected");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onError(ConnectionInterface $conn, \Exception $e)
|
public function onError(ConnectionInterface $conn, \Exception $e)
|
||||||
{
|
{
|
||||||
echo "[默认路径] An error has occurred: {$e->getMessage()}\n";
|
ws_echo("[默认路径] An error has occurred: {$e->getMessage()}", 'error');
|
||||||
$conn->close();
|
$conn->close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -318,7 +407,7 @@ class DefaultWebSocketController implements MessageComponentInterface
|
|||||||
// 注册默认的/ws路径测试控制器
|
// 注册默认的/ws路径测试控制器
|
||||||
// 默认测试路径同样不限制 Host
|
// 默认测试路径同样不限制 Host
|
||||||
$ratchetApp->route('/ws', new DefaultWebSocketController(), array('*'), '');
|
$ratchetApp->route('/ws', new DefaultWebSocketController(), array('*'), '');
|
||||||
echo "已注册默认WebSocket测试控制器到路径 /ws\n";
|
ws_echo("已注册默认WebSocket测试控制器到路径 /ws");
|
||||||
|
|
||||||
// 缓存WebSocket服务器信息(可选,用于其他服务查询)
|
// 缓存WebSocket服务器信息(可选,用于其他服务查询)
|
||||||
$serverInfoKey = 'websocket_server_info';
|
$serverInfoKey = 'websocket_server_info';
|
||||||
@@ -330,123 +419,124 @@ $cache->set($serverInfoKey, [
|
|||||||
'registered_addons' => $registeredAddons
|
'registered_addons' => $registeredAddons
|
||||||
], 0); // 0表示永久缓存,直到手动删除
|
], 0); // 0表示永久缓存,直到手动删除
|
||||||
|
|
||||||
echo "WebSocket服务器已启动,监听地址: ws://{$httpHost}:{$port}\n";
|
ws_echo("WebSocket服务器已启动,监听地址: ws://{$httpHost}:{$port}");
|
||||||
|
|
||||||
// 显示已注册WebSocket控制器的addon路径
|
// 显示已注册WebSocket控制器的addon路径
|
||||||
echo "\n已注册WebSocket控制器的addon路径:\n";
|
ws_echo("\n已注册WebSocket控制器的addon路径:");
|
||||||
if (!empty($registeredAddons)) {
|
if (!empty($registeredAddons)) {
|
||||||
foreach ($registeredAddons as $addonName) {
|
foreach ($registeredAddons as $addonName) {
|
||||||
echo " - ws://{$httpHost}:{$port}/ws/{$addonName} (已注册)\n";
|
ws_echo(" - ws://{$httpHost}:{$port}/ws/{$addonName} (已注册)");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
echo " - 暂无已注册的WebSocket控制器\n";
|
ws_echo(" - 暂无已注册的WebSocket控制器");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 显示未注册WebSocket控制器的addon路径
|
// 显示未注册WebSocket控制器的addon路径
|
||||||
echo "\n未注册WebSocket控制器的addon路径:\n";
|
ws_echo("\n未注册WebSocket控制器的addon路径:");
|
||||||
if (!empty($unregisteredAddons)) {
|
if (!empty($unregisteredAddons)) {
|
||||||
foreach ($unregisteredAddons as $addonName) {
|
foreach ($unregisteredAddons as $addonName) {
|
||||||
echo " - ws://{$httpHost}:{$port}/ws/{$addonName} (未注册)\n";
|
ws_echo(" - ws://{$httpHost}:{$port}/ws/{$addonName} (未注册)");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
echo " - 所有已启用且目录存在的addon都已注册WebSocket控制器\n";
|
ws_echo(" - 所有已启用且目录存在的addon都已注册WebSocket控制器");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 显示未启用的addon
|
// 显示未启用的addon
|
||||||
echo "\n未启用的addon:\n";
|
ws_echo("\n未启用的addon:");
|
||||||
if (!empty($disabledAddons)) {
|
if (!empty($disabledAddons)) {
|
||||||
foreach ($disabledAddons as $addonName) {
|
foreach ($disabledAddons as $addonName) {
|
||||||
echo " - {$addonName} (未启用)\n";
|
ws_echo(" - {$addonName} (未启用)");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
echo " - 所有addon都已启用\n";
|
ws_echo(" - 所有addon都已启用");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 显示目录不存在的addon
|
// 显示目录不存在的addon
|
||||||
echo "\n目录不存在的addon:\n";
|
ws_echo("\n目录不存在的addon:");
|
||||||
if (!empty($missingDirAddons)) {
|
if (!empty($missingDirAddons)) {
|
||||||
foreach ($missingDirAddons as $addonName) {
|
foreach ($missingDirAddons as $addonName) {
|
||||||
echo " - {$addonName} (目录不存在)\n";
|
ws_echo(" - {$addonName} (目录不存在)");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
echo " - 所有已启用的addon目录都存在\n";
|
ws_echo(" - 所有已启用的addon目录都存在");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加定期检查数据库连接的机制
|
// 添加定期检查数据库连接的机制
|
||||||
// 创建一个单独的进程来定期检查和维护数据库连接
|
// 创建一个单独的进程来定期检查和维护数据库连接
|
||||||
// 添加信号处理,确保当父进程停止时,子进程也会被终止
|
// 添加信号处理,确保当父进程停止时,子进程也会被终止
|
||||||
if (extension_loaded('pcntl')) {
|
if (extension_loaded('pcntl')) {
|
||||||
// 记录子进程PID
|
// 记录子进程PID
|
||||||
$dbMaintenancePid = null;
|
$dbMaintenancePid = null;
|
||||||
|
|
||||||
// 创建数据库连接维护子进程
|
|
||||||
$pid = pcntl_fork();
|
|
||||||
if ($pid == -1) {
|
|
||||||
echo "[WebSocket服务器] 无法创建子进程来维护数据库连接\n";
|
|
||||||
} elseif ($pid == 0) {
|
|
||||||
// 子进程:定期检查数据库连接
|
|
||||||
echo "[WebSocket服务器] 启动数据库连接维护进程\n";
|
|
||||||
|
|
||||||
// 每30秒检查一次数据库连接
|
// 创建数据库连接维护子进程
|
||||||
$checkInterval = 30; // 秒
|
$pid = pcntl_fork();
|
||||||
|
if ($pid == -1) {
|
||||||
// 设置子进程的信号处理
|
ws_echo("[WebSocket服务器] 无法创建子进程来维护数据库连接", 'error');
|
||||||
pcntl_signal(SIGTERM, function() {
|
} elseif ($pid == 0) {
|
||||||
echo "[数据库维护子进程] 收到终止信号,正在退出...\n";
|
// 子进程:定期检查数据库连接
|
||||||
exit(0);
|
ws_echo("[WebSocket服务器] 启动数据库连接维护进程");
|
||||||
});
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
// 检查是否有信号需要处理
|
|
||||||
pcntl_signal_dispatch();
|
|
||||||
|
|
||||||
try {
|
// 每30秒检查一次数据库连接
|
||||||
// 尝试执行一个简单的数据库查询来测试连接
|
$checkInterval = 30; // 秒
|
||||||
$addon_model = new Addon();
|
|
||||||
$addon_model->getAddonList([], 'name', 1, 1); // 只查询一条记录
|
// 设置子进程的信号处理
|
||||||
echo "[数据库维护子进程] 数据库连接正常\n";
|
pcntl_signal(SIGTERM, function() {
|
||||||
} catch (\Exception $e) {
|
ws_echo("[数据库维护子进程] 收到终止信号,正在退出...");
|
||||||
echo "[数据库维护子进程] 数据库连接异常: {$e->getMessage()}\n";
|
exit(0);
|
||||||
echo "[数据库维护子进程] 尝试重新初始化数据库连接...\n";
|
});
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
// 检查是否有信号需要处理
|
||||||
|
pcntl_signal_dispatch();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 重新初始化应用和数据库连接
|
// 尝试执行一个简单的数据库查询来测试连接
|
||||||
$app->initialize();
|
$addon_model = new Addon();
|
||||||
$cache = $app->cache;
|
$addon_model->getAddonList([], 'name', 1, 1); // 只查询一条记录
|
||||||
echo "[数据库维护子进程] 重新初始化应用成功\n";
|
ws_echo("[数据库维护子进程] 数据库连接正常");
|
||||||
} catch (\Exception $retryEx) {
|
} catch (\Exception $e) {
|
||||||
echo "[数据库维护子进程] 重新初始化应用失败: {$retryEx->getMessage()}\n";
|
ws_echo("[数据库维护子进程] 数据库连接异常: {$e->getMessage()}", 'error');
|
||||||
|
ws_echo("[数据库维护子进程] 尝试重新初始化数据库连接...");
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 重新初始化应用和数据库连接
|
||||||
|
$app->initialize();
|
||||||
|
$cache = $app->cache;
|
||||||
|
ws_echo("[数据库维护子进程] 重新初始化应用成功");
|
||||||
|
} catch (\Exception $retryEx) {
|
||||||
|
ws_echo("[数据库维护子进程] 重新初始化应用失败: {$retryEx->getMessage()}", 'error');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 等待指定的时间间隔
|
||||||
|
sleep($checkInterval);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// 父进程:记录子进程PID并设置信号处理
|
||||||
|
$dbMaintenancePid = $pid;
|
||||||
|
|
||||||
// 等待指定的时间间隔
|
// 设置父进程的信号处理
|
||||||
sleep($checkInterval);
|
pcntl_signal(SIGINT, function() use ($dbMaintenancePid) {
|
||||||
|
ws_echo("[WebSocket服务器] 收到终止信号,正在停止...");
|
||||||
|
|
||||||
|
// 如果子进程存在,发送终止信号
|
||||||
|
if ($dbMaintenancePid) {
|
||||||
|
ws_echo("[WebSocket服务器] 停止数据库连接维护进程");
|
||||||
|
posix_kill($dbMaintenancePid, SIGTERM);
|
||||||
|
// 等待子进程退出
|
||||||
|
pcntl_wait($status);
|
||||||
|
}
|
||||||
|
|
||||||
|
ws_echo("[WebSocket服务器] 已停止");
|
||||||
|
exit(0);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// 父进程:记录子进程PID并设置信号处理
|
|
||||||
$dbMaintenancePid = $pid;
|
|
||||||
|
|
||||||
// 设置父进程的信号处理
|
|
||||||
pcntl_signal(SIGINT, function() use ($dbMaintenancePid) {
|
|
||||||
echo "[WebSocket服务器] 收到终止信号,正在停止...\n";
|
|
||||||
|
|
||||||
// 如果子进程存在,发送终止信号
|
|
||||||
if ($dbMaintenancePid) {
|
|
||||||
echo "[WebSocket服务器] 停止数据库连接维护进程\n";
|
|
||||||
posix_kill($dbMaintenancePid, SIGTERM);
|
|
||||||
// 等待子进程退出
|
|
||||||
pcntl_wait($status);
|
|
||||||
}
|
|
||||||
|
|
||||||
echo "[WebSocket服务器] 已停止\n";
|
|
||||||
exit(0);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// 运行服务器
|
// 运行服务器
|
||||||
echo "[WebSocket服务器] 启动主服务器进程\n";
|
ws_echo("[WebSocket服务器] 启动主服务器进程");
|
||||||
echo "\n默认测试路径:\n";
|
ws_echo("\n默认测试路径:");
|
||||||
echo " - ws://{$httpHost}:{$port}/ws (默认路径,用于连接测试)\n";
|
ws_echo(" - ws://{$httpHost}:{$port}/ws (默认路径,用于连接测试)");
|
||||||
echo "按 Ctrl+C 停止服务器\n";
|
ws_echo("按 Ctrl+C 停止服务器");
|
||||||
|
ws_info("WebSocket服务器已启动,监听地址: ws://{$httpHost}:{$port}");
|
||||||
$ratchetApp->run();
|
$ratchetApp->run();
|
||||||
|
|||||||
Reference in New Issue
Block a user