超简单的HTTP套接字服务器,用PHP编写,行为出乎意料


Ultra simple HTTP socket server, written in PHP, behaving unexpectedly

tldr;

  1. PHP中的极小流套接字服务器
  2. 行为很奇怪,因为有时它成功地服务于HTTP请求,而有时在同一进程内失败
  3. 在不同浏览器之间的行为很奇怪 -几乎每次在Chrome中失败,而在IE11中从未失败

代码:

$server = stream_socket_server("tcp://0.0.0.0:4444", $errno, $errorMessage);
if ($server === false) 
    throw new UnexpectedValueException("Could not bind to socket: $errorMessage");
$e = "'r'n";
$headers = array(
    "HTTP/1.1 200 OK",
    "Date: " . date('D') . ', ' . date('m') . ' '  . date('M') . ' ' . date('Y') . ' ' . date('H:i:s') . ' GMT' ,
    'Server: MySpeedy',
    'Connection: close',
    'Content-Type: text/plain',
    'Content-Length: 2'
);
$headers = implode($e, $headers) . $e .  $e .'ok';
for (;;) 
{
    $client = stream_socket_accept($server);
    if ($client) 
    {
        echo 'Connection accepted from '.stream_socket_get_name($client, false) . $e;
        fwrite($client, $headers);
        fclose($client);
    }
}

给我这个http响应(telnet结果):

HTTP/1.1 200 OK
Date: Fri, 11 Nov 2015 20:09:02 GMT
Server: MySpeedy
Connection: close
Content-Type: text/plain
Content-Length: 2
ok

这让我得出了以下结果:

  • Chrome中的ERR_CONNECTION_RESET,几乎每次(可能20-30分之一请求得到预期响应)
  • Firefox中的The connection was reset,约为1/2-3请求
  • 每次都在Internet Explorer 11中得到正确的预期响应(是的,IE在某些方面是最好的)

我做错了什么?是由http头(我不知道我是否格式化错误)还是由套接字循环或..决定的。。?

您不从客户端读取HTTP请求,而是简单地发送响应并关闭连接。但是,在仍有数据要读取时关闭套接字将导致连接重置发送回客户端,这就是您在Chrome中看到的ERR_connection_reset。其他浏览器可能会有不同的行为,如果浏览器能够在处理重置之前显示响应,这也是一个时间问题。

要解决此问题,请在关闭套接字之前先读取客户端的完整请求。