php套接字的结果不一致

php套接字的结果不一致,php,json,sockets,connection-timeout,Php,Json,Sockets,Connection Timeout,我面临着一个我对PHP套接字不太了解的问题;我得到了“不一致”的结果,因为通信似乎不稳定,我不知道如何设置流超时 长话短说:我试图获得一个套接字服务器,一些客户端通过VPN连接到该服务器(我知道,我的服务器现在不是多线程的…,我需要更多这方面的技能!)以获得最新的配置,为我今天关注的asterisk生成多个配置文件。服务器是一个简单的PHP套接字脚本socket.PHP,客户端由网关action.PHP组成,用于任何模块,这些模块使用各自应用程序/目录中PHP cli脚本中的类。例如,我有mod

我面临着一个我对PHP套接字不太了解的问题;我得到了“不一致”的结果,因为通信似乎不稳定,我不知道如何设置流超时

长话短说:我试图获得一个套接字服务器,一些客户端通过VPN连接到该服务器(我知道,我的服务器现在不是多线程的…,我需要更多这方面的技能!)以获得最新的配置,为我今天关注的asterisk生成多个配置文件。服务器是一个简单的PHP套接字脚本
socket.PHP
,客户端由网关
action.PHP
组成,用于任何模块,这些模块使用各自应用程序/目录中PHP cli脚本中的类。例如,我有
modules/pbx/app/update_sip.php
,它使用
modules/pbx/classes/PbxGenerateConfig.php
通过
modules/api/classes/ApiServer.php
socket客户端从socket服务器json响应获取(并写入)配置文件。我希望大家都清楚;)

这里是一些摘录(请不要犹豫,要求更多,因为我真的不知道我错过了什么…)

socket.php

<?php

chdir(dirname(__FILE__));

require_once('classes/_Autoload_.php');
require_once('config.php');


function convertObjectToArray ($object) {
    if(!is_object($object) && !is_array($object))
        return $object;

    return array_map('convertObjectToArray', (array) $object);
}


set_time_limit (0);
$address = '0.0.0.0';
$port = 9000;

$sock = socket_create(AF_INET, SOCK_STREAM, 0); // 0 for  SQL_TCP
socket_set_option($sock, SOL_SOCKET, SO_RCVTIMEO, array('sec' => 60, 'usec' => 0));

@socket_bind($sock, 0, $port) or die("Cannot bind to $address:$port\n");  //0 forlocalhost
socket_listen($sock);

#TODO fork child processes to support multiple clients & classes loads on-the-fly

while (true)
{
$client  = socket_accept($sock);
$input   = socket_read($client, 16384000);

$command = convertObjectToArray(json_decode($input));

$authentication = Database::get('management')->selectOne(array('table'     => 'components',
                                                               'fields'    => 'id,name',
                                                               'condition' => "management_access_key LIKE '{$command['access_key']}'"));

if (empty($authentication))
    $response = array('request' => array('command'=>$command['command'], 'arguments'=>$command_args, 'status' => 'error'),
                      'result'  => 'Authentication failed : invalid access key');

else if(!empty($command))
{
    $get_security_policies = Database::get('management')->selectAll(array('table'     => 'components_security_policies',
                                                                          'fields'    => 'class',
                                                                          'condition' => "component = {$authentication['id']}"));

    $security_policies = array();
    foreach ($get_security_policies as $policy) { $security_policies[] = $policy['class']; }

    unset($command['access_key']);

    if (isset($command['command']))
    {
        $command_call = explode('/',$command['command']);
        $command_args = $command; unset($command_args['command']);

        if (in_array($command_call[0],$security_policies))
        {

            #TODO check if command/function exists + try/catch
            $output = $command_call[0]::$command_call[1]($command_args);

            $response = array('request' => array('command'=>$command['command'], 'arguments'=>$command_args, 'status' => 'success'),
                              'result'  => $output);
        }

        else $response = array('request' => array('command'=>$command['command'], 'arguments'=>$command_args, 'status' => 'success'),
                               'result'  => 'Action forbidden by security policies for this access key');


    }

    else
    {
        $response = array('request' => array('command'=>NULL, 'arguments'=>NULL, 'status' => 'error'),
                          'result'  => 'Command not set');
    }


}

else $response = array('request' => array('command'=>NULL, 'arguments'=>NULL, 'status' => 'error'),
                       'result'  => 'No command received');

echo "==================== COMMAND RECEIVED ====================\n";
echo "FROM: C{$authentication['name']} (C{$authentication['id']})\n";
print_r($command); echo "\n";
echo "--------------------  RESPONSE SENT   --------------------\n";
print_r($response); echo "\n";
echo "==========================================================\n\n\n\n";

socket_write($client, json_encode($response));
socket_close($client);
}

// Close the master sockets
socket_close($sock);
<?php
$usage = "Usage : ./{$argv[0]} <module> <class> <method> [arguments]";

if (!isset($argv[1])) die("Error : Missing argument 'module'\n$usage\n\n");

chdir(dirname(__FILE__));
if (!is_dir('../modules/'.$argv[1])) die("Error : Module '{$argv[1]}' is not installed\n\n");

fclose(STDIN);  $STDIN  = fopen('/dev/null', 'r');
#fclose(STDOUT); $STDOUT = fopen('/var/log/management-client-'.$argv[1].'.out.log',    'a');
fclose(STDERR); $STDERR = fopen('/var/log/management-client-'.$argv[1].'.error.log', 'a');

error_reporting(E_ALL);
ini_set('display_errors', true);
#ini_set('display_errors', false);

#require_once('../config/'.$argv[1].'.php');
foreach (glob("../config/*.php") as $file) { include_once($file); }
require_once('lib/cliArgsParser.php');
require_once('lib/classAutoLoader.php');

if (php_sapi_name() === 'cli')
{
$arguments = core_cliArgsParser($argv);

if (empty($arguments[2])) die("Error : Missing argument 'class'\n$usage\n\n");
if (empty($arguments[3])) die("Error : Missing argument 'method'\n$usage\n\n");

$class_name = ucfirst($arguments[1]);
$class_arguments = $arguments;
unset($class_arguments[0],$class_arguments[1],$class_arguments[2],$class_arguments[3]);

$result = $class_name::action($arguments[2])->$arguments[3]($class_arguments);
#echo json_encode($result);
print_r($result);
}
else die ('Error : Can be executed exclusively from CLI');
php /usr/local/management-client/core/action.php pbx generateConfig generateSip --type=carriers --location=/ramdisk/
(...)
public function generateSip ($args)
{
    $types = array('carriers','users');

    if (empty($args['location'])) return "Error : 'location' required\n";
    if (!in_array(@$args['type'],$types)) return "Error : type '".@$args['type']."' not supported (can be : ".implode(',',$types).")\n";

    # carriers
    if ($args['type'] == 'carriers')
    {
        $response = Api::action('server')->request(array('command'=>'PbxServer/getSipConfig', 'type'=>$args['type']));

        if ($response->result->status == 'success')
        {
            $fh = fopen(rtrim($args['location'],'/').'/sip_carriers.conf','w');
            $file_content = '';

            foreach ($response->result->data as $sip_trunk)
            {
                $file_content .="[{$sip_trunk->code}]  ; {$sip_trunk->name}\n"
                              . "{$sip_trunk->sip_settings}\n\n";
            }

            fwrite($fh,utf8_encode($file_content));
            fclose($fh);

            return "Sip {$args['type']} successfully updated\n";
        }

        else return "Sip update error\n";
    }
(...)
class ApiServer extends Api
{

public function request ($command)
{

    global $CONFIG;

    $command['access_key'] = $CONFIG['api']['access']['key'];

    $ret = '';
    $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
              socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, array('sec' => 60, 'usec' => 0));

    if ($socket === false) die("Cannot create socket : ".socket_strerror(socket_last_error())."\n");


    $result = @socket_connect($socket, $CONFIG['api']['access']['host'], $CONFIG['api']['access']['port']);

    if ($result === false)
    {
        return "Cannot connect to {$CONFIG['api']['access']['host']}:{$CONFIG['api']['access']['port']} : ".socket_strerror(socket_last_error($socket))."\n";
    }

    $cmd = json_encode($command);

    socket_write($socket, $cmd, strlen($cmd));
    #stream_set_timeout($socket, 60);

    while ($out = socket_read($socket, 16384000))
    {
        $ret = json_decode($out);
    }

    socket_close($socket);

    return $ret;
}


}
PbxGenerateConfig.php

<?php

chdir(dirname(__FILE__));

require_once('classes/_Autoload_.php');
require_once('config.php');


function convertObjectToArray ($object) {
    if(!is_object($object) && !is_array($object))
        return $object;

    return array_map('convertObjectToArray', (array) $object);
}


set_time_limit (0);
$address = '0.0.0.0';
$port = 9000;

$sock = socket_create(AF_INET, SOCK_STREAM, 0); // 0 for  SQL_TCP
socket_set_option($sock, SOL_SOCKET, SO_RCVTIMEO, array('sec' => 60, 'usec' => 0));

@socket_bind($sock, 0, $port) or die("Cannot bind to $address:$port\n");  //0 forlocalhost
socket_listen($sock);

#TODO fork child processes to support multiple clients & classes loads on-the-fly

while (true)
{
$client  = socket_accept($sock);
$input   = socket_read($client, 16384000);

$command = convertObjectToArray(json_decode($input));

$authentication = Database::get('management')->selectOne(array('table'     => 'components',
                                                               'fields'    => 'id,name',
                                                               'condition' => "management_access_key LIKE '{$command['access_key']}'"));

if (empty($authentication))
    $response = array('request' => array('command'=>$command['command'], 'arguments'=>$command_args, 'status' => 'error'),
                      'result'  => 'Authentication failed : invalid access key');

else if(!empty($command))
{
    $get_security_policies = Database::get('management')->selectAll(array('table'     => 'components_security_policies',
                                                                          'fields'    => 'class',
                                                                          'condition' => "component = {$authentication['id']}"));

    $security_policies = array();
    foreach ($get_security_policies as $policy) { $security_policies[] = $policy['class']; }

    unset($command['access_key']);

    if (isset($command['command']))
    {
        $command_call = explode('/',$command['command']);
        $command_args = $command; unset($command_args['command']);

        if (in_array($command_call[0],$security_policies))
        {

            #TODO check if command/function exists + try/catch
            $output = $command_call[0]::$command_call[1]($command_args);

            $response = array('request' => array('command'=>$command['command'], 'arguments'=>$command_args, 'status' => 'success'),
                              'result'  => $output);
        }

        else $response = array('request' => array('command'=>$command['command'], 'arguments'=>$command_args, 'status' => 'success'),
                               'result'  => 'Action forbidden by security policies for this access key');


    }

    else
    {
        $response = array('request' => array('command'=>NULL, 'arguments'=>NULL, 'status' => 'error'),
                          'result'  => 'Command not set');
    }


}

else $response = array('request' => array('command'=>NULL, 'arguments'=>NULL, 'status' => 'error'),
                       'result'  => 'No command received');

echo "==================== COMMAND RECEIVED ====================\n";
echo "FROM: C{$authentication['name']} (C{$authentication['id']})\n";
print_r($command); echo "\n";
echo "--------------------  RESPONSE SENT   --------------------\n";
print_r($response); echo "\n";
echo "==========================================================\n\n\n\n";

socket_write($client, json_encode($response));
socket_close($client);
}

// Close the master sockets
socket_close($sock);
<?php
$usage = "Usage : ./{$argv[0]} <module> <class> <method> [arguments]";

if (!isset($argv[1])) die("Error : Missing argument 'module'\n$usage\n\n");

chdir(dirname(__FILE__));
if (!is_dir('../modules/'.$argv[1])) die("Error : Module '{$argv[1]}' is not installed\n\n");

fclose(STDIN);  $STDIN  = fopen('/dev/null', 'r');
#fclose(STDOUT); $STDOUT = fopen('/var/log/management-client-'.$argv[1].'.out.log',    'a');
fclose(STDERR); $STDERR = fopen('/var/log/management-client-'.$argv[1].'.error.log', 'a');

error_reporting(E_ALL);
ini_set('display_errors', true);
#ini_set('display_errors', false);

#require_once('../config/'.$argv[1].'.php');
foreach (glob("../config/*.php") as $file) { include_once($file); }
require_once('lib/cliArgsParser.php');
require_once('lib/classAutoLoader.php');

if (php_sapi_name() === 'cli')
{
$arguments = core_cliArgsParser($argv);

if (empty($arguments[2])) die("Error : Missing argument 'class'\n$usage\n\n");
if (empty($arguments[3])) die("Error : Missing argument 'method'\n$usage\n\n");

$class_name = ucfirst($arguments[1]);
$class_arguments = $arguments;
unset($class_arguments[0],$class_arguments[1],$class_arguments[2],$class_arguments[3]);

$result = $class_name::action($arguments[2])->$arguments[3]($class_arguments);
#echo json_encode($result);
print_r($result);
}
else die ('Error : Can be executed exclusively from CLI');
php /usr/local/management-client/core/action.php pbx generateConfig generateSip --type=carriers --location=/ramdisk/
(...)
public function generateSip ($args)
{
    $types = array('carriers','users');

    if (empty($args['location'])) return "Error : 'location' required\n";
    if (!in_array(@$args['type'],$types)) return "Error : type '".@$args['type']."' not supported (can be : ".implode(',',$types).")\n";

    # carriers
    if ($args['type'] == 'carriers')
    {
        $response = Api::action('server')->request(array('command'=>'PbxServer/getSipConfig', 'type'=>$args['type']));

        if ($response->result->status == 'success')
        {
            $fh = fopen(rtrim($args['location'],'/').'/sip_carriers.conf','w');
            $file_content = '';

            foreach ($response->result->data as $sip_trunk)
            {
                $file_content .="[{$sip_trunk->code}]  ; {$sip_trunk->name}\n"
                              . "{$sip_trunk->sip_settings}\n\n";
            }

            fwrite($fh,utf8_encode($file_content));
            fclose($fh);

            return "Sip {$args['type']} successfully updated\n";
        }

        else return "Sip update error\n";
    }
(...)
class ApiServer extends Api
{

public function request ($command)
{

    global $CONFIG;

    $command['access_key'] = $CONFIG['api']['access']['key'];

    $ret = '';
    $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
              socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, array('sec' => 60, 'usec' => 0));

    if ($socket === false) die("Cannot create socket : ".socket_strerror(socket_last_error())."\n");


    $result = @socket_connect($socket, $CONFIG['api']['access']['host'], $CONFIG['api']['access']['port']);

    if ($result === false)
    {
        return "Cannot connect to {$CONFIG['api']['access']['host']}:{$CONFIG['api']['access']['port']} : ".socket_strerror(socket_last_error($socket))."\n";
    }

    $cmd = json_encode($command);

    socket_write($socket, $cmd, strlen($cmd));
    #stream_set_timeout($socket, 60);

    while ($out = socket_read($socket, 16384000))
    {
        $ret = json_decode($out);
    }

    socket_close($socket);

    return $ret;
}


}
ApiServer.php
class ApiServer extends Api
{

public function request ($command)
{

    global $CONFIG;

    $command['access_key'] = $CONFIG['api']['access']['key'];

    $ret = '';
    $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
              socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, array('sec' => 60, 'usec' => 0));

    if ($socket === false) die("Cannot create socket : ".socket_strerror(socket_last_error())."\n");


    $result = @socket_connect($socket, $CONFIG['api']['access']['host'], $CONFIG['api']['access']['port']);

    if ($result === false)
    {
        return "Cannot connect to {$CONFIG['api']['access']['host']}:{$CONFIG['api']['access']['port']} : ".socket_strerror(socket_last_error($socket))."\n";
    }

    $cmd = json_encode($command);

    socket_write($socket, $cmd, strlen($cmd));
    #stream_set_timeout($socket, 60);

    while ($out = socket_read($socket, 16384000))
    {
        $ret = json_decode($out);
    }

    socket_close($socket);

    return $ret;
}


}
谢谢,
CL

我已经发展了很长一段时间,但我一个字也不懂你写的,也不知道你想完成什么,或者你认为哪里出了问题。再加上那堵代码墙,我想现在没有人能给你什么帮助了。我甚至什么都不懂…数据库::get('management')…你的数据库类和get函数定义在哪里?我正试图通过PHP套接字从远程服务器获取一些配置数据(通过客户端和服务器之间的VPN建立),但这就像我只得到了json响应的一部分…不确定它是否与网络相关,但向客户端和服务器添加一些超时似乎更好(从对套接字/服务器的4个请求中获得至少2个完整结果),所以我想我现在需要在流本身上添加一些超时,因为在本地没有任何问题!问题只在我通过VPN时出现(25ms,pings似乎稳定)。@CodeLover当我调用Database::时,这些类由include Autoload.php自动加载,get()用于查找要查询的正确数据库。