我正面临一个问题,我对PHP套接字并不是很了解;由于通信似乎不稳定,我得到“非一致”的结果,我无法想象如何设置流超时。
长篇短篇小说:我试图获得一个客户端通过VPN连接的套接字服务器(我知道,我的服务器现在不是多线程的...,我需要更多的技能!)来获取我今天关注的最新配置为星号生成多个配置文件。服务器是一个简单的PHP套接字脚本socket.php
,客户端由任何模块的网关action.php
组成,这些模块使用各自应用程序/目录中的php-cli脚本的类。所以我有例如modules/pbx/app/update_sip.php
,它使用modules/pbx/classes/PbxGenerateConfig.php
通过modules/api/classes/ApiServer.php
套接字客户端从套接字服务器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);
action.php的
<?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');
update_sip.php
php /usr/local/management-client/core/action.php pbx generateConfig generateSip --type=carriers --location=/ramdisk/
PbxGenerateConfig.php
(...)
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";
}
(...)
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