H2S97: Live code reading walkor/workerman: An asynchronous event driven PHP socket framework

Hu: A cursory glance at the work of Github/u/walkor/workerman and one can gleam the insight of an exceptionalIQ:

walkor has the idea to enable generalized | connections, using a browser, and php.web-server to a variety of protocols, thereby unlocking the power of the modern browser<Mozilla, a-r> Hu: A wide range of real-time protocol connections can be established via a generalized HTTP.req-paradigm, and payloads can be generalized in frame.php. Most all these protocols # will rely in TCP-conn, and employ both ports, sockets, and PHP’s stream.function-lib. Here, we will read walkor’s implementation and see which insights we can adopt from both the code-line and the overall architecture #

H3S1: Stream_socket_server:

Hu: I will start by thematically looking for the socket initiator. As it turns out, this function is located in only one file: main/Worker.php<2,554-lines> #, which is a general handler file for a variety of different protocol types. Therefore, walkor has extrapolated these stream functions, built-in to PHP, as of being a higher order of generalization than Web-Sockets itself, and I would be of agreement in this evaluation<Turing-shared><WP.MIC-H2S75>

H4S1: Line 2,231, function listen()

$this->_mainSocket = \stream_socket_server($local_socket, $errno, $errmsg, $flags, $this->_context);

H5S1: $local_socket: Line 2219, same function:

$local_socket = $this->parseSocketAddress();

H6S1: This function, labeled as “parse local socket address”, is defined in line 2284

protected function parseSocketAddress() {
// there is a complex procedure to build a socket:
Line 2310: return self::BUILD_IN_TRANSPORTS[$this->transport] . ":" . $address;
// We already have the address, that we are plugging into stream_socket_server as of 11/9/22. 

Hu: It seems like walkor writes with functions what should probably hard-coded or pseudo.hard-coded and supplemented with user-education<WP.MIC-H2S45>.

H5S2: At the end of listen(), whose main purpose # is to run stream_socket_server, walkor runs resumeAccept(), which “resume accept new connections”, and “register a listener<$this->_mainSocket> to be notified when server socket is ready to read“. Hu: It was not clear to me<WP.MIC-H2S92>whether or not stream_socket_server is perpetual=syn | continuous or discontinuous, and walkor seems to handle it discontinuously; after the new server socket is created, he activates resumeAccept, which triggers a meta-arm that will run something that is continuous, and notifies $this->_mainSocket that fread<80%, anthro 11/9/22> should be run. I think this is what walkor means that his app is “Event-based”, ie it handles stream_socket_server discontinuously<Turing>, but this does not imply that the stream socket is inherently discontinuous. resumeAccept itself calls a separate | function, onReadable, which is defined at /Events/Event.php<H3S5-H4S4>

H3S2: Stream_socket_client:

Hu: Like with stream_socket_server, _client exists in only one file, /Connection/AsyncTcpConnection.php<371-lines>

H4S1: Line 195, function connect():

$this->_socket = \stream_socket_client("tcp://{$this->_remoteHost}:{$this->_remotePort}",

H5S1: $this->_remoteHost:

Hu: I’m less concerned with where walkor finds these variables for now, as this is not the issue I’m stuck on as of 11/9/22, but I might double check this later #

H5S2: $this->_remotePort:

H4S2: Calls to $this->_socket:

$this->_socket can be found 16 | times in this document; it looks like from this client | side | doc, all the interactions are to use this strim-obj. This is consistent with https://www.php.net/manual/en/function.stream-socket-client.php and<WP.MIC-H2S77><pseudo-anthro>

H4S3: Writing to the endpoint:

Hu: I could not find any mentions of fwrite in this particulardoc, and will check if walkor uses a different function to write to the endpoint #

H3S3: Fwrite/read:

Hu: The implementation of fwrite/read really differentiates walkor’s architecture from Schweitzer’s; both are located in /Connection/TcpConnection.php

H4S1: “Sends data on the connection.”

Line 328: public function send($send_buffer, $raw = false)
// Later this function #:
Line 364: $len = @\fwrite($this->_socket, $send_buffer);

H4S2: “Base write handler.”

// in function baseWrite(), more concise than send(); 
Line 710: $len = @\fwrite($this->_socket, $this->_sendBuffer);

H4S3: “Base read handler”:

Line 568: public function baseRead($socket, $check_eof = true)
Line 585: $buffer = @\fread($socket, self::READ_BUFFER_SIZE);

H3S3: Function.ref-chain<Turing>:

H3S4: Parsing the READ-ME:


According to the READ-ME, this line creates a new Websocket server:

$ws_worker = new Worker('websocket://');

Hu: A similar workflow, including the Worker() function, is used to launch an HTTP or TCP server, in Worker. After setting up a multidimensional | variable named $ws_worker, the file depicted on READ-ME “Worker::runAll();” which will execute all of these functions, over at main/Worker.php, under the class “Worker”:

    public static function runAll()

Hu: Note that this exact list of function is run in the HTTP and TCP launch cases, also.

H3S5: Event-notifications #:

H4S1: onConnect:


$ws_worker->onConnect = function ($connection) {
    echo "New connection\n";

H4S2: onMessage:

$ws_worker->onMessage = function ($connection, $data) {
    // Send hello $data
    $connection->send('Hello ' . $data);

H4S3: onClose:

$ws_worker->onClose = function ($connection) {
    echo "Connection closed\n"; 

H4S3: onReadable($stream, $func)

/Events/Event.php line 146. This function returns a boolean, taking the arguments $this->_mainSocket, the value of which was assigned by stream_socket_server on Worker.php, and $this, ‘acceptTcpConnection’, where acceptTcpConnection($socket) is # a function defined in line 2435, of Worker.php, that “accept a connection on server socket”, and runs:

$new_socket = \stream_socket_accept($socket, 0, $remote_address);

At the bottom of acceptTcpConnection is ($this->onConnect)($connect), “try to emit onConnect callback”<H4S1>.

H5S1: Where is stream_socket_client in this workflow?

// rage.quit-temp








Leave a Reply

Your email address will not be published. Required fields are marked *