我正在尝试启动 PHP 作为服务,我运行以下命令:
C:\Windows\system32>sc create PHPSERVER binpath= "C:\php\php-cgi.exe -b 127.0.0.1:9000" start= auto
[SC] CreateService SUCCESS
但我遇到的问题是,当我打开服务管理器并尝试启动服务时出现此错误:
Windows 无法在本地计算机上启动 PHPSERVER 服务。
错误 1053:服务未及时响应启动或控制请求。
有什么方法可以修复此问题,使其正常工作?
答案1
答案2
您遇到的错误是因为 SCM(Windows 服务管理器)尝试与服务通信,以了解其状态(“我正在启动”、“我已经启动”、“我正在运行”…)或发送命令(“请暂停”、“请停止”)
您必须管理这些交换,这可以通过 PECL 来完成鍵盤扩大。
我第一次在这里读到它:https://stackoverflow.com/a/8703371/913967
我的答案仅适用于 Windows。在 Linux 上,你可以拦截 SIGINT 和 SIGTERM 等 OS 信号。
重要的
由于这是 Windows 扩展,因此您应始终检查这些功能是否适用于您当前的环境。例如,使用:
if ( function_exists('win32_start_service_ctrl_dispatcher') ) {
// OK, I'm on Windows I can execute win32_xxx functions
}
初始化服务
// Start the dialog with the SCM
win32_start_service_ctrl_dispatcher('myservice');
// If our program takes a long time before being ready,
// we can tell the SCM that we are starting (unnecessary if it's fast)
win32_set_service_status(WIN32_SERVICE_START_PENDING);
// OK, we are ready
win32_set_service_status(WIN32_SERVICE_RUNNING);
停止服务
在程序的末尾,就在exit()
或其他内容之前,表明服务已关闭:
win32_set_service_status(WIN32_SERVICE_STOP);
拦截 SCM 消息并按其要求执行
您必须定期收听消息,以了解是否必须执行某些操作。这是通过以下方式完成的:
$scmAction = win32_get_last_control_message();
这可以添加到无限循环或其他任何循环中(由计时器激活......)
然后,您可以处理给定的订单,并在完成时通知 SCM(以便 SCM 知道您按照他的要求做了)例如:
switch ($scmAction) {
// Asked to stop
case WIN32_SERVICE_CONTROL_SHUTDOWN:
case WIN32_SERVICE_CONTROL_STOP:
win32_set_service_status(WIN32_SERVICE_STOP_PENDING);
// ...
// do your stuff here to stop your service
// ...
win32_set_service_status(WIN32_SERVICE_STOPPED);
break;
// Asked to pause
case \WIN32_SERVICE_CONTROL_PAUSE:
// ...
// do your stuff here to pause your service
// (for example: keep your infinite loop, but do not process things in it)
// ...
\win32_set_service_status(\WIN32_SERVICE_PAUSED);
break;
// Asked to continue (after a pause)
case \WIN32_SERVICE_CONTROL_CONTINUE:
// ...
// do your stuff here to reactivate your service
// ...
\win32_set_service_status(\WIN32_SERVICE_RUNNING);
break;
// Asked for our current state
case \WIN32_SERVICE_CONTROL_INTERROGATE:
$state = $paused ? WIN32_SERVICE_PAUSED : WIN32_SERVICE_RUNNING;
\win32_set_service_status($state);
}
将脚本安装为服务
这可以使用 win32service 扩展来完成,或者手动使用sc.exe
使用 win32service 扩展
如果您想在 PHP 中管理服务的安装/删除,这可能会很有趣。例如,如果您想实现一些命令行参数,例如:
php my_script.php --install
php my_script.php --remove
添加服务 (调整名字和脚本地址)
$result = win32_create_service([
'service' => 'myservice',
'display' => 'My PHP Service',
'path' => 'php.exe',
'params' => __DIR__.'\\my-service.php',
]);
if ($result != WIN32_NO_ERROR) {
// Something went wrong
// For the error explanation, compare $result with the error codes constants
// in https://www.php.net/manual/en/win32service.constants.errors.php
}
请注意,我们没有在php.exe
此处定义路径...因此必须在 WindowsPATH
环境变量中找到此路径。或者,如果您知道绝对地址并且确定它不会在您的系统上更改,请指定绝对地址。
要删除服务:
$result = win32_delete_service('myservice');
if ($result != WIN32_NO_ERROR) {
// Same as above
}
使用 sc.exe
使用帮助:https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/sc-create
注意:执行这些命令时您必须具有管理员权限。
安装服务
sc create myservice type= own start= auto binpath= "php.exe -f C:\Path\to\my\php-script.php" displayname= "My PHP Service"
(和以前一样,我没有在这里设置路径php.exe
。如果它不在您的PATH
环境变量中,请添加它。
删除服务
sc delete myservice
测试服务
必须使用管理员权限
启动服务:
net start myservice
或者:
sc start myservice
停止服务:
net stop myservice
或者:
sc stop myservice
查询服务状态:
sc query myservice
请求暂停/恢复:
sc pause myservice
sc continue myservice
(sc query
之后再做一次以了解状态)