Ultra simple HTTP socket server, written in PHP, b

2019-01-20 17:51发布

问题:

tldr;

  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

code:

$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);
    }
}

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 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).

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..?

回答1:

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.