13

我刚试过这段代码:

<?php
set_time_limit(0);

$address = '176.9.117.136';
$port = 9000;

$sock = socket_create(AF_INET, SOCK_STREAM, 0);
socket_bind($sock, $address, $port) or die('Could not bind to address');

while(1)
{
    socket_listen($sock);
    $client = socket_accept($sock);

    $input = socket_read($client, 1024);
    echo $input;

    $output = 'URL: http://ip-of-my-server:9000/
HTTP/1.1 200 OK
Date: Tue, 10 Jul 2012 16:58:23 GMT
Server: TestServer/1.0.0 (PHPServ)
Last-Modified: Fri, 06 Jul 2012 14:29:58 GMT
ETag: "13c008e-1b9-4c42a193de580"
Accept-Ranges: bytes
Content-Length: 441
Vary: Accept-Encoding
Content-Type: text/html

';
    socket_write($client, $output);

    socket_close($client);
}

socket_close($sock);
?>

但有一个问题。Apache 不使用 $output 的内容作为标头,而是返回自己的标头...

我不知道为什么,因为我通过以下命令执行脚本:php webserv.php.

但是它实际上可以工作,因为当我http://ip-of-my-server:9000/从浏览器加载页面时,它会向我显示客户端在服务器上发送的标头,并将内容返回$output给客户端(我的浏览器)。

如果可能的话,我只想在 PHP 中创建自己的网络服务器。我只想知道如何在没有 Apache 的情况下运行它,这样我就可以管理自己的 HTTP 标头。

4

3 回答 3

18

是否有理由在 PHP 中实现 HTTP 服务器(所有事物)?没有线程等。这会很痛苦……(除非这是某种学术问题……)

PHP 5.4 附带一个内置的网络服务器。也许这就是你要找的……</p>


更新:

虽然我理解你学习这类东西的动机,但我相信你在使用 PHP 尝试这类东西时走错了路。PHP 并不是真正为长时间运行的进程而设计的(就像服务器一样),它不适合并行处理(线程)。即使是多处理也需要PCNTL,特别是pcntl_fork()并将您的教育漫游限制为基于 Unix 的系统(但这可能不是问题)。

如果您的目标是了解服务器如何处理并发性,我建议使用专为此设计的语言(Erlang、Go、Scala ......)。或者使用一种至少可以模拟并行处理的语言(Python、Ruby,……[有点,因为它们的 GIL])。

如果您的目标是了解 HTTP(让我告诉您 HTTP 是一头野兽,如果您正在超越 HTTP/1.0 并希望做对),那么摆弄 PHP 可能会很好,如果它是您唯一的语言如果是这样,请查看这篇(可悲的德语)关于PHP 中的 Socket Servers 的文章中的示例代码(聊天服务器),以获取运行集中在实际 HTTP 上的基本套接字内容。


更新 2:

要回答您关于标题的问题……我不知道 apache 将如何适应您问题中描述的场景。但是我看到您正在使用换行符来分隔标题,并使用双换行符来分隔标题与正文。除非您已将 php 文件保存\r\n为默认换行符(windows 样式),否则您的 header-part 格式错误,因此将被识别为正文。根据 http 客户端(用户代理,可能是您的浏览器、curl 或其他),这可能会被处理为“插入一些默认标头”。用换行符替换并重\r\n试。

如果您的服务器可以从 Internet 访问,请尝试使用一些标头测试工具来验证您的 HTTP 是否正确。如果它是 localhost-only,看看会curl -I http://ip-of-my-server:9000吐出什么。

于 2012-07-10T17:32:10.757 回答
2

我认为您web-server在这种情况下的意思只是服务器和客户端或排序之间的一些套接字通信。我使用 PHP 和套接字的经验是使用 Flash 代理客户端。

这包括在页面的某处嵌入一个 1x1px 的 flash 像素,并将其用作 flash 像素、Javascript 和 PHP 套接字服务器之间的桥梁。(一旦您知道了 ActionScript 的工作原理, socket 通信就变得轻而易举了)。此方法也是您获得最大浏览器兼容性的唯一方法(即使是更高级的 websocket 框架,如socket.io也使用此 flash 像素方法作为后备)。

另一种选择当然是WebSockets,类似于在这个站点上用于实时刷新功能的那些。Stack Overflow 上甚至还有一个专门针对它的标签。

如果您想尝试使用 PHP 创建一个套接字服务器,那么您的客户端必须不仅仅是您的浏览器。

希望这会引导您朝着正确的方向前进...

于 2012-07-10T17:50:12.077 回答
1

您最初尝试的代码非常接近,但只需要进行一些小改动:

<?php
set_time_limit(0);

$address = '127.0.0.1';
$port = 80;

$sock = socket_create(AF_INET, SOCK_STREAM, 0);
socket_bind($sock, $address, $port) or die('Could not bind to address');

echo "\n Listening On port $port For Connection... \n\n";

while(1)
{
    socket_listen($sock);
    $client = socket_accept($sock);

    $input = socket_read($client, 1024);

    $incoming = array();
    $incoming = explode("\r\n", $input);

    $fetchArray = array();
    $fetchArray = explode(" ", $incoming[0]);

    $file = $fetchArray[1];
    if($file == "/"){ 

        $file = "index.html"; 

    } else {

        $filearray = array();
        $filearray = explode("/", $file);
        $file = $filearray[1];
    }

echo $fetchArray[0] . " Request " . $file . "\n"; 

$output = "";
$Header = "HTTP/1.1 200 OK \r\n" .
"Date: Fri, 31 Dec 1999 23:59:59 GMT \r\n" .
"Content-Type: text/html \r\n\r\n";

$Content = file_get_contents($file);
$output = $Header . $Content;

    socket_write($client,$output,strlen($output));
    socket_close($client);
}

此处的代码现在将恢复请求数据包的标头以查找请求的文件,然后它将转到该文件的本地目录。就目前而言,这仅适用于 html,因此它不支持图像,但它可以作为一个非常轻量级的 Web 服务器。它目前默认为 index.html,所以只需保存它,将一些 html 文件放在同一目录中,然后将浏览器指向它。

干杯希望这有帮助!

于 2014-03-01T20:42:26.073 回答