5

我似乎无法让这个工作。

所以我正在尝试为我的游戏编写一个脚本,该脚本连接到服务器,传递一些游戏名称/类型/玩家/等参数。然后服务器脚本根据需要设置游戏服务器的新实例,运行服务器的新实例,找到它正在运行的端口,并将所有这些信息发送回游戏。

我已经完成了脚本需要执行服务器游戏 exe 的部分,并获取它的 PID(所以我可以获取它正在使用的端口等)。

服务器脚本是一个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

开发机器:带有 SP1 的 Windows 7 Ultimate

服务器机器:Windows Server 2008 R2

4

2 回答 2

9

我设法得到它。我使用 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");

?>
于 2012-11-12T04:07:45.247 回答
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 服务的更多信息。

于 2012-11-08T14:02:29.197 回答