peachpiecompiler / peachpie

PeachPie - the PHP compiler and runtime for .NET and .NET Core
https://www.peachpie.io
Apache License 2.0
2.33k stars 202 forks source link

Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object #1014

Closed avriltank closed 2 years ago

avriltank commented 2 years ago

Error:

Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object.
   at Pchp.Library.Streams.SocketStream.get_CanReadWithoutLock()
   at Pchp.Library.Streams.PhpStreams.stream_select(PhpArray& read, PhpArray& write, PhpArray& except, Int32 tv_sec, Int32 tv_usec)
   at Worker.run() in D:\chenfa\csharp_learn_proj\eventExtensionProj\phptest\main.php:line 55
   at CallSite.Target(Closure , CallSite , PhpValue , Context , CallerTypeParam )
   at System.Dynamic.UpdateDelegates.UpdateAndExecuteVoid3[T0,T1,T2](CallSite site, T0 arg0, T1 arg1, T2 arg2)
   at <Root>.main_php.<Main>(Context <ctx>, PhpArray <locals>, Object this, RuntimeTypeHandle <self>) in D:\chenfa\csharp_learn_proj\eventExtensionProj\phptest\main.php:line 120
   at <Script>.Main(String[] args)

Demo code:

<?php

class Worker{
    //Monitor socket
    protected $socket = NULL;

     //All socket connections
    protected $allSockets = array();

     //Connection event callback
    public $onConnect = NULL;

     //Disconnection event callback
    public $onClose = NULL;

     //Receive message event callback
    public $onMessage = NULL;

    public function __construct($socket_address) {
         //Create a socket monitor
        $this->socket = stream_socket_server($socket_address);

         //Set to non-blocking
        stream_set_blocking($this->socket, 0);

         //Add socket monitoring to allSockets
        $this->allSockets[(int)$this->socket] = $this->socket;
    }

    public function run() {
        while(true) {
             //Do not listen to writable events and out-of-band data events
            $write = $except = array();
             //Monitor all socket events
            $read = $this->allSockets;
             //The entire process is blocked here, continuously listening for readable events
             //The parameters here are all passed by reference, and the passed value will be changed in the function
            $ret = stream_select($read, $write, $except, 0, 100000000);

             //Handle all readable events
            foreach ($read as $index => $socket) {
                 //If it is a listening socket, it means there is a new connection here
                if ($socket === $this->socket) {
                     //Get a new connection through stream_socket_accept
                    $new_conn_socket = stream_socket_accept($socket);

                    if ($this->onConnect) {
                         // Trigger the callback of the connection event and pass the current connection to the callback function
                        call_user_func($this->onConnect, $socket);
                    }
                     //Record this socket connection so that sream_select can monitor readable events
                    $this->allSockets[(int)$new_conn_socket] = $new_conn_socket;
                } else
                 //If the readable event is not a listening socket, it means that the corresponding client has data sent
                {
                     //Read data from the connection
                    $buffer = fread($socket, 65535);
                     //If the data is empty, it means the client has been disconnected
                    if ('' === $buffer || false === $buffer) {
                         //Try to trigger the onClose callback
                        if ($this->onClose) {
                            call_user_func($this->onClose, $socket);
                        }
                        fclose($socket);
                         //Close the socket connection and delete from allSockets
                        unset($this->allSockets[(int)$socket]);
                        continue;
                    }
                     //Indicates a normal connection, the message has been read and handed over to the callback function for processing
                    if ($this->onMessage) {
                        call_user_func($this->onMessage, $socket, $buffer);
                    }
                }
            }
        }
    }
}

$worker = new Worker('tcp://0.0.0.0:9898');

$worker->onConnect = function ($conn) {
     //echo'New connection is coming';
};
$worker->onClose = function ($conn) {
     //echo'The connection is disconnected';
};
$worker->onMessage = function ($conn, $message) {
    //message is over here
    $http_resonse = <<<EOF
HTTP/1.1 200 OK
Content-type: text/html; charset=utf-8
Content-Length: 5

hello
EOF;
    fwrite($conn, $http_resonse);
};

$worker->run();

Beanchmark command

 wrk -c100 -t16 -d10s http://127.0.0.1:9898