dtgta48604 2015-02-04 13:12
浏览 81

PHP fgets无限期运行

I have built myself a simple HTTP request object, very basic

class Request {

    protected $hostname;
    protected $port = 80;
    protected $method = 'GET';
    protected $uri = '/';
    protected $headers = array();
    protected $body;
    protected $handle;
    protected $response;

    public function __construct() {
        $cookies = null;
        foreach (\Cookie::getAll() as $k => $v) {
            $cookies .= urlencode($k) . '=' . urlencode($v) . '; ';
        }
        $this->setHeader('Cookie', substr($cookies, 0, -2));
    }

    public function setHostname($name, $ssl = false) {
        if (filter_var(gethostbyname($name), FILTER_VALIDATE_IP)) {
            $this->hostname = ($ssl ? 'ssl://' : null) . $name;
            $this->setHeader('Host', $name);

            return true;
        }
        return false;
    }

    public function setPort($port) {
        if ($port >= 1 && $port <= 65535) {
            $this->port = (int)$port;
            return true;
        }
        return false;
    }

    public function setMethod($method) {
        $methods = [
            'GET' => true,
            'POST' => true,
            'PUT' => true,
            'DELETE' => true
        ];

        if (isset($methods[$method])) {
            $this->method = strtoupper($method);
            return true;
        }
        return false;
    }

    public function setUri($uri) {
        $this->uri = $uri;
        return true;
    }

    public function setHeader($key, $value) {
        $this->headers[$key] = $value;
        return true;
    }

    public function removeHeader($key) {
        unset($this->headers[$key]);
        return true;
    }

    public function setBody($body) {
        $this->body = $body;
        return true;
    }

    public function send($async = false, $timeout = 30) {
        $errno = null;
        $errstr = null;

        $this->setHeader('Content-Length', strlen($this->body));
        if($async){
            $this->setHeader('Connection', 'Close');
        }

        $this->response = null;
        $this->handle = fsockopen($this->hostname, $this->port, $errno, $errstr, $timeout);
        if (!$this->handle) {
            throw new \Exception($errstr, $errno);
        }

        $headers = null;
        foreach ($this->headers as $key => $value) {
            $headers .= $key . ': ' . $value . "
";
        }

        $request = "{$this->method} {$this->uri} HTTP/1.1
{$headers}
" . $this->body;

        fwrite($this->handle, $request);

        if ($async) {
            fclose($this->handle);
            return;
        }

        while (!feof($this->handle)) {
            echo $this->response . ' dgd<br/><br/><br/>';
            $this->response .= fgets($this->handle, 8192);
        }
        fclose($this->handle);
    }

    public function getResponse() {
        return $this->response;
    }
}

When I send an "asynchronous" there's no problems but when I try to get the response I get maximum execution time exceeded error. I added an echo into the response-reading loop to debug and it only runs once. What may the problem be?

$r = new \Request();
$r->setHostname('localhost');
$r->setUri('/test.php');
$r->send();

echo "<pre>" . print_r($r, true) . "</pre>";

test.php

echo 'Test complete.';

Response source of the initial request

 dgd<br/><br/><br/><br />
<b>Fatal error</b>:  Maximum execution time of 30 seconds exceeded in <b>....\Request.php</b> on line <b>98</b><br />

Where line 98 is

$this->response .= fgets($this->handle, 8192);
  • 写回答

2条回答 默认 最新

  • douyi8732 2015-02-04 13:52
    关注

    The fgets() will read data from the socket and complete the read under several conditions such as end of file, the length - 1 number of characters read, or socket close.

    The first thing you could try is to change your length to a much smaller value to see if you can get multiple reads. This will tell you whether the loop is working and the fgets() is not seeing the proper read termination behavior from the client that is sending data through the socket which is being read by the fgets().

    What I suspect is that the client which is sending data is not closing the socket after sending the data.

    The HTTP protocol is really designed to be stateless. The basic procedure is that the client should open a socket, send an HTTP request, get an HTTP response from the server, and then close the socket. However you can modify this procedure with the proper changes in the client and the server so as to maintain a connection sending and receiving data such as JSON or XML.

    Since a TCP connection is a simple byte stream, any coordination between client and server where a connection is maintained must be implemented with some agreement by the client and the server as to the structure of the data. Using JSON or XML is pretty straightforward as those have messages have a structure where you know the beginning and the ending of a message.

    For simple HTTP using the standard HTTP procedure, the end of the message is communicated by the closing of the socket by the client after it receives the HTTP response from the server. This tells the server that the communication is done.

    评论

报告相同问题?

悬赏问题

  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置
  • ¥15 有没有研究水声通信方面的帮我改俩matlab代码
  • ¥15 ubuntu子系统密码忘记
  • ¥15 信号傅里叶变换在matlab上遇到的小问题请求帮助
  • ¥15 保护模式-系统加载-段寄存器
  • ¥15 电脑桌面设定一个区域禁止鼠标操作