我有一个运行Apache 2.2.3和PHP 5.4.8的CentOS 5.9盒子。
我正在尝试使用 PHP 设置服务器,以便另一台服务器上的 C 应用程序可以轻松地从我们的 Web 服务器查询一些信息。
我还希望能够将数据包发送到本地服务器 - 从同一网络服务器 - 以方便地控制服务器。
问题是,当通过浏览器/apache访问服务器和客户端时,客户端永远无法连接。当我通过 CLI 执行客户端或服务器时,它突然起作用。
我在 Ubuntu 盒子上测试了相同的代码,它可以正常工作。
对于测试/调试,服务器会在 30 秒后自动关闭。
澄清一下:
- 浏览器转到服务器启动.php
- 浏览器转到客户端.php
- 结果:客户端.php继续加载,直到服务器启动.php达到 30 秒关闭,然后响应"连接被拒绝"
- 浏览器转到serverstart2.php,它使用exec,passthru或system('php -f serverstart.php');
- 浏览器转到客户端.php
- 结果:不起作用。客户端挂起,直到服务器启动.php 30 秒后关闭。
- CLI: php -f serverstart.php
- 浏览器转到客户端.php
- 结果:有效
- 浏览器转到服务器启动.php
- CLI: php -f 客户端.php
- 结果:有效
- 浏览器转到服务器启动.php
- CLI:回显"测试"| nc localhost 8000
- 结果:有效
客户端.php
<?php
$client = stream_socket_client("tcp://localhost:8000", $errno, $errorMessage);
if ($client === false) {
echo "Failed to connect: $errorMessage";
}
fwrite($client, "This is a test" . PHP_EOL);
echo stream_get_contents($client);
fclose($client);
服务器启动.php
<?PHP
$server = stream_socket_server("tcp://0.0.0.0:8000", $errno, $errorMessage);
if ($server === false) {
throw new UnexpectedValueException("Could not bind to socket: $errorMessage");
}
$start = microtime(true);
while((microtime(true) - $start) < 30) { // 30 second timeout
$client = @stream_socket_accept($server, 1);
if ($client) {
echo 'Client Found';
$message = fgets($client, 1024);
echo 'Client said:' . $message;
fwrite($client, 'The local time is ' . date('n/j/Y g:i a') . PHP_EOL);
fclose($client);
}
}
任何人都知道这里发生了什么,以及我如何让它通过浏览器调用两者?
编辑:我想补充一点,盒子上没有防火墙。 iptables 显示为空白,SELinux 被禁用。
相当延迟的回答,但不知道你的 apache 和 php 配置,或者你的 Ubuntu 和 CentOS 配置之间的差异。我相信权限可能是您问题的根源。
例如,当您通过 CLI 运行脚本并使用su apache; php serverstart.php;
时,您应该获得与从浏览器运行时相同的结果。而不是以根用户身份运行 CLI。这是由于 apache 无权连接指定的 ip/端口。
此外,请确保您的端口 8000 未被 Apache(或其他服务)使用,因为它是许多配置中的常见端口,并且在尝试通过 php 访问它时可能会被阻止。通常在您的 Apache 配置中的某个地方,它将包含 Listen *:8000 或类似内容。
EG:http://localhost:8000 -> Apache -> php -> fsockopen('tcp://localhost:8000')
(已经在使用中),php 超时,端口被打开,然后客户端.php响应连接被拒绝。
您可以通过创建一个脚本 (test.php) 来检查冲突<?php sleep(120);
该脚本仅包含浏览到 http://localhost/test.php
.php然后在 test.php 处于休眠状态时从 CLI 执行 servertstart。
同样在 serverstart 中.php请确保在脚本末尾执行fclose($server);
或stream_socket_shutdown($server, STREAM_SHUT_RDWR);
,以确保服务器不会处于不可用状态。还要在 while 结束时至少添加一个usleep(500)
,以防止额外的 CPU 使用率。如果返回 false,您也应该退出循环stream_socket_accept
因为它指示发生了错误,而不是从循环中调用@stream_socket_accept
。
while($timer < 30 && ($client = stream_socket_accept($server, 1))){
$timer = (microtime(true) - $start);
//code here
}
如果上述情况没有帮助,我认为默认情况下,您的 Apache Web 服务器充当 PHP 的包装器,并使用 apache 的用户和组权限执行。这就是为什么您的 Web 文件通常具有用户组 apache 权限,其中目录权限为 750,文件权限为 640。这允许 apache 访问并拒绝匿名访问虚拟主机目录中的目录和文件,然后当它读取 PHP 文件时,apache 执行 php 并将结果输出为 text/html。但是,Apache无法访问其他系统资源
您可以通过从一个脚本中执行echo exec('whoami');
并从浏览器导航到它来检查正在运行的用户。
权限问题有几种解决方法,其中大多数是不良做法,并且会在服务器上存在安全漏洞。
您可以通过在连接之前从 serverstart 和客户端.php中执行umask(0);
来解决此问题.php。这意味着创建的任何内容都将使用 0777 权限,包括套接字。或者,您可以尝试在 serverstart 和 client 上设置chmod(755)
.php.php以查看允许匿名用户对文件执行权限是否可以解决问题。
否则,您可以考虑为您的 Web 服务(如 suexec
或 php-fpm
)创建一个包装器,并通过 Apache 以用户名/用户组和正确的掩码设置使用 fastcgi 运行它。然后,确保您的用户有权在指定的 ip/端口上打开连接。