【问题标题】:Create a webserver in PHP (without Apache)在 PHP 中创建一个网络服务器(没有 Apache)
【发布时间】:2012-07-10 05:55:27
【问题描述】:

我刚试过这段代码:

<?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 标头。

【问题讨论】:

  • 以防万一你不知道,PHP5.4 附带一个内置的 Web 服务器,所以你不必做这种事情......
  • 这似乎是在重新发明轮子。我向你保证,那里有很多轮子。
  • rdlowrey:我知道,是的。 Wug:这只是为了学习......我永远不会将它用作生产网络服务器。我只想创建我自己的,以了解它是如何从 A 到 Z 工作的。
  • 您是否有在同一台机器上运行的 apache 实例?您可能想尝试禁用它并重试...
  • 有Nanoweb,还有PEARs HTTP_Server供参考。

标签: php apache http sockets webserver


【解决方案1】:

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

PHP 5.4 附带 built-in webserver。也许这就是你要找的……


更新:

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

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

如果您的目标是理解 HTTP(让我告诉您 HTTP 是一头野兽,如果您正在超越 HTTP/1.0 并且想要正确地做到这一点),那么摆弄 PHP 可能没问题,如果它是唯一的语言你很坚定。如果是这样,请查看Socket Servers in PHP 上这篇(可悲的德语)文章中的示例代码(聊天服务器),以获取运行专注于实际 HTTP 的基本套接字内容。


更新 2:

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

如果您的服务器可以通过 Internet 访问,请尝试使用 header test tools 来验证您的 HTTP 是否正确。如果它是 localhost-only,请查看 curl -I http://ip-of-my-server:9000 吐出的内容。

【讨论】:

  • 是的,这是一种学术性的东西,但它只适合我。我只是想在PHP的使用上学习并走得更远。
  • +1 - 我不知道谁投了反对票,但他必须是个白痴才能反对。必须创建 HTTP 服务器不仅仅是“下一个,下一个,下一个”任务。特别是如果您使用 PHP 进行操作。
  • @tftd 我知道,但我会重复一遍,这只是为了学习如何去做。我永远不会将它用于生产网站...
  • 了解它的工作原理很棒,这就是让你成为一名优秀程序员的原因,学习何时使用你深入学习的东西是智慧,你只有通过经验才能获得。不要害怕尝试一些东西,但要使用常识。
  • @MathieuDumoulin 今天已经用了 10 个小时了,我尝试了很多东西,很多不同的方法,这个似乎是最好的(我在第一条消息中提供的代码)。但是Apache有这个问题我真的解决不了……
【解决方案2】:

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

这涉及在页面某处嵌入一个 1x1px 的 flash 像素,并将其用作 flash 像素、Javascript 和 PHP 套接字服务器之间的桥梁。 (socket通信真的是a breeze with ActionScript once you know how it works)。此方法也是您获得最大浏览器兼容性的唯一方法(即使是更高级的 websocket 框架,如 socket.io 也使用此 flash 像素方法作为后备)。

另一个选项当然是WebSockets,类似于本网站上用于实时刷新功能的选项。 Stack Overflow 上甚至还有 a tag dedicated to it

如果您想尝试使用 PHP 创建一个 socket 服务器,您的客户端必须不是 只是您的浏览器。

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

【讨论】:

  • 我不确定我是否了解所有内容,但是如何创建一个“完整的”网络服务器,而客户端只是一个网络浏览器?
  • 如果这正是您要寻找的,那么我必须同意其他人所说的重新发明轮子...如果您只是想研究与 PHP 的套接字通信,那么也许你应该从比 HTTP 服务器更小的东西开始......
  • 不,我真的想用 PHP 创建一个 HTTP 服务器。我不想“只”了解套接字。
【解决方案3】:

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

<?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 文件放在同一目录中,然后将浏览器指向它。

干杯希望这会有所帮助!

【讨论】:

    猜你喜欢
    • 2017-03-22
    • 1970-01-01
    • 2013-10-18
    • 2017-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-02
    相关资源
    最近更新 更多