超简单的 HTTP 套接字服务器,用 PHP 编写,行为异常

2022-01-17 00:00:00 sockets http-headers http php apache

tldr;

  1. PHP
  2. 中非常小的流套接字服务器
  3. 表现得很奇怪,因为它有时会成功处理 HTTP 请求,而有时会在同一个进程中失败
  4. 在不同的浏览器中表现得很奇怪 - 几乎每次都在 Chrome 中失败,而在 IE11
  1. very minimal stream socket server in PHP
  2. acts strange since sometimes it successfully serves HTTP request and sometimes fails within the very same process
  3. acts strange across different browsers - almost every time fails in Chrome and never in 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 = "
";
$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 结果):

gives me this http response (telnet results):

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

这导致我得到这些结果:

And that leads me to these results:

  • ERR_CONNECTION_RESET 在 Chrome 中,几乎每次(可能是 20-30 中的 1请求得到预期的响应)
  • 连接被重置在 Firefox 中,大约 1 in 2-3请求
  • 每次在 Internet Explorer 11 中都能得到正确的预期响应(是的,IE 是最好的).
  • ERR_CONNECTION_RESET in Chrome, almost every time (maybe 1 in 20-30 requests get expected response)
  • The connection was reset in Firefox, approximately 1 in 2-3 requests
  • Correct, expected response in Internet Explorer 11 every time (yay, IE is the best in something).

我做错了什么?是 http 标头(我不能说我的格式是否错误)还是 socket loop 或..?

What am I doing wrong? Is it up to http headers (I couldn't say if I've formatted them incorrectly) or socket loop or..?

推荐答案

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

You don't read the HTTP request from the client but instead simply send your response and close the connection. But closing the socket while there are still data to read will cause a connection reset send back to the client and that's what you will see in Chrome with ERR_CONNECTION_RESET. Other browsers might behave differently and it is also a timing issue if the browser can display the response before handling the reset.

要修复它,请先从客户端读取完整的请求,然后再关闭套接字.

To fix it first read the full request from the client before you close the socket.

相关文章