在PHP中启动Windows进程并获取它的PID?

时间:2012-11-08 13:15:19

标签: php windows

我似乎无法实现这一目标。

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

我已经完成了脚本需要执行服务器游戏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

2 个答案:

答案 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服务的更多信息。