我似乎无法实现这一目标。
所以我试图为我的游戏编写一个脚本,连接到服务器,传递游戏名称/类型/玩家等的一些参数。然后服务器脚本根据需要设置游戏服务器的新实例,运行服务器的新实例,找到它正在运行的端口,并将所有信息发送回游戏。
我已经完成了脚本需要执行服务器游戏exe的部分,并获得它的PID(所以我可以得到它使用的端口等)。< / p>
服务器脚本是一个PHP脚本,用于执行服务器的新实例。 (PHP似乎是一个不错的选择,而且相对于我所知)。
脚本必须能够完成执行,同时保持游戏服务器在后台运行。
能够同时运行多个游戏服务器是必要的。
我尝试使用proc_open
,但是它给出了错误的进程PID,这使得它无用。 (但是,它确实执行了程序)
<?php
$startDir = "C:/Torque/My Projects/Grim/game";
$runExe = "$startDir/Grimwood.exe";
$envars = " -dedicated -mission \"core/levels/Empty Terrain.mis\"";
$runPath = $runExe . $envars;
chdir($startDir);
$descriptorspec = array(
0 => array("pipe", "r"), // stdin is a pipe that the child will read from
1 => array("pipe", "w"), // stdout is a pipe that the child will write to
);
$prog = proc_open($runPath, $descriptorspec, $pipes, $startDir, NULL);
sleep(4);
if (is_resource($prog))
{
$stats = proc_get_status($prog);
$pid = $stats['pid'];
$task = shell_exec("tasklist /fi \"PID eq $pid\"");
echo("\nProcess: \n$task"); // echos cmd.exe, not process ran
}
?>
它打印的PID属于它执行它的控制台窗口,而不是它实际执行的程序。
接下来,我尝试使用MS脚本宿主WScript.Shell
及其exec
/ run
方法。
<?php
$startDir = "C:/Torque/My Projects/Grim/game";
$runExe = "$startDir/Grimwood.exe";
$envars = " -dedicated -mission \"core/levels/Empty Terrain.mis\"";
$runPath = $runExe . $envars;
chdir($startDir);
try
{
$WshShell = new COM("WScript.Shell");
// gets right process ID
// but process doesn't start properly with params
$oExec = $WshShell->exec($runPath);
echo("PID: " . $oExec->ProcessId);
sleep(4);
// executes properly
// but doesn't return PID
$oExec = $WshShell->run($runPath);
echo("PID: " . $oExec->ProcessId);
}
catch (Exception $e)
{
// never gets hit
echo("Failed to execute");
}
?>
运行exec命令,它会给出正确的PID,但程序没有正确启动(只显示一个空白的终端窗口,什么都不做)。
运行run命令,它正确启动程序(显示它在终端窗口中应该显示的所有文本),但命令不会返回PID。
对此事的任何帮助将不胜感激。我不确定我对WScript.Shell->exec
命令做错了什么,因为它没有正确执行,所以对此问题的所有帮助都将不胜感激。
如果可能的话,我想使用proc_open
方法,因为如果我们想要将任何服务器内容移到* nix上,它会更加跨平台。
感谢您的时间,我希望一些聪明的头脑可以指出我正确的方向。
PHP版本:5.4.3
Dev Machine:Windows 7旗舰版SP1
服务器计算机:Windows Server 2008 R2
答案 0 :(得分:6)
我设法得到它。我使用proc_open执行,它返回游戏服务器运行的PPID(cmd.exe可执行文件)。
当start /b
退出时,cmd.exe一旦执行了程序,PPID就是游戏服务器唯一应该拥有的东西,因此其余部分找到PID相对容易。
当一次制作多个实例,并且多个实例已在运行时,这也适用。
这是使用proc_open获取PID的结束脚本,如果有其他人想知道这个线程并且可能碰巧需要它:
<?php
$startDir = "C:/Torque/My Projects/Grim/game";
$runExe = "$startDir/Grimwood.exe";
$envars = " -dedicated -mission \"core/levels/Empty Terrain.mis\"";
$runPath = $runExe . $envars;
chdir($startDir);
$descriptorspec = array (
0 => array("pipe", "r"),
1 => array("pipe", "w"),
);
if ( is_resource( $prog = proc_open("start /b " . $runPath, $descriptorspec, $pipes, $startDir, NULL) ) )
{
$ppid = proc_get_status($prog)['pid'];
}
else
{
echo("Failed to execute!");
exit();
}
$output = array_filter(explode(" ", shell_exec("wmic process get parentprocessid,processid | find \"$ppid\"")));
array_pop($output);
$pid = end($output);
echo("\nProcess ID: $pid ; Parent's Process ID: $ppid\n");
// returns right process
$task = shell_exec("tasklist /fi \"PID eq $pid\"");
echo("\n\nProcess: \n$task\n\n");
// returns no process found
$task = shell_exec("tasklist /fi \"PID eq $ppid\"");
echo("\n\nParent Process: \n$task\n\n");
?>
答案 1 :(得分:1)
我相信你可以通过这种方式得到你想要的结果,因为你正在为Windows操作系统开发。
首先使您的.exe作为服务运行。 (我相信这是语法)
sc create SERVICENAME binpath=PATH_TO_EXE
然后我相信你可以:
win32_start_service('SERVICENAME');
sleep(4);
$serviceStatus = win32_query_Service_status('SERVICENAME');
var_dump($serviceStatus);
// or
echo $serviceStatus[ProcessId];
PS - 请注意我没有测试过这个。但我相信这会奏效。试一试。
同时访问此链接http://www.php.net/manual/en/book.win32service.php以获取有关Windows服务的更多信息。