OpenSwoole\Server->on('Receive', fn)

Latest version: pecl install openswoole-22.1.2 | composer require openswoole/core:22.1.5

Declaration

<?php OpenSwoole\Server->on('Receive', Callable $callback)

Parameters

event

The event callback name.

callback

Callable event function.

Return

success

If success, it returns true, otherwise it returns false.

Description

Execute the callback function when the Server is receiving TCP packages, allowing you to process a new request and its data. This event is one of the main callbacks predominantly used, it is the first entry point for processing new request data on a OpenSwoole server.

The callback function registered for the Receive event is executed inside a Worker Process where its data is also sent.

Under the TCP mode, there is no boundary of the data transmits between Client and Server. It is necessary to set the configuration eof_check, length_check or http_protocol on how to split the data stream into packets or you can convert the data stream into packets manually. By default the same fd will be assigned to the same worker process, making it easy to splice data together one after another, if you use dispatch_mode 3, then the request data may be sent to separate worker processes and then you won't be able to sequentially splice the data together.

Protocol parsing and data stream splitting

OpenSwoole Server has built-in parsers to parse HTTP, HTTP2, WebSocket, MQTT packets, the packets are then passed into the receive callback function:

  • open_http_protocol
  • open_http2_protocol
  • open_websocket_protocol
  • open_mqtt_protocol

You can enable these parsers on the server, for example:

<?php
$server->set([
  'open_mqtt_protocol' => true
]);

Even though OpenSwoole allows you to manually splice data together, OpenSwoole has a range of built in parsers for TCP network protocols like HTTP, websockets and MQTT but OpenSwoole does support 2 different customer protocols:

  • EOF Terminator: The End Of File (EOF) terminator allows you to splice data together based on a string of special characters placed at the end of each data packet. This indicates that the data packet has ended, for example some protocols use \r\n as their EOF string. However, performance may be slow with this method as the OpenSwoole server will need to parse every string to check for the EOF for each byte of data.

  • Fixed Header and Body: The method of fixing the header is very common and can often be seen in server-side programs. This method works by setting the amount of data the server needs to accept to get the complete data in the header of the request. The data Packet header specifies a length of the entire data to be received, typically using 2/4 byte integers to represent data length. After the server receives the packet length header, it can accurately control how much data needs to be received according to the length value to be a complete data packet. OpenSwoole has support for this protocol and the configuration is very easy to setup.

The data packet is processed in the onReceive callback function. When the protocol processing is set, the onReceive event will be triggered only when a complete data packet is received . After the client has set up the protocol processing, calling $client->recv() no longer needs to pass in the length. The recv function returns after receiving the complete packet or an error occurs.

Other parsing related settings:

open_length_check

By enabling open_length_check, you have to set package_max_length. Then the server parser ignores the data exceeding package_max_length, and will close the connection.

open_eof_check

Ignores the data after the EOF string is found. Then the server parser ignores the data exceeding package_max_length, and closes the connection.

open_eof_split

Split the data stream into packets with EOF. You can set the EOF to be \r\n or any other string to act as the terminator for when to stop receiving data packets.

For more information about server configuration options, please see the server configuration documentation for more detailed information and other related options

Data Transformation

Transform the data into the $fd and reactorId of Receive callback function:

<?php
$fd = unpack('L', pack('N', ip2long($addr['address'])))[1];
$reactorId = ($addr['server_socket'] << 16) + $addr['port'];

Example

<?php
$server = new OpenSwoole\Server("127.0.0.1", 9501);

$server->on('Start', function($server)
{
    echo "Server is started.\n";
});

$server->on('Shutdown', function($server)
{
    echo "Server is shutting down.\n";
});

$server->on('Connect', function($server, $fd)
{
    echo "New connection established: #{$fd}.\n";
});

$server->on('Receive', function(OpenSwoole\Server $server, int $fd, int $reactorId, string $data)
{
    $server->send($fd, "Echo to #{$fd}: \n".$data);
    $server->close($fd);
});

$server->on('Close', function($server, $fd)
{
    echo "Connection closed: #{$fd}.\n";
});

$server->start();

The example above starts a new OpenSwoole TCP server which has registered a number of different callback events, once started, the server listens on IP 127.0.0.1 using the port 9501 and any incoming data will trigger the Receive event so that the server can process the data. You can run this example locally if you have OpenSwoole installed, place the example inside a file called server.php and run it using php server.php. You will see output in the console to say that the server has started, a message for when a new client connects, a Receive event message which outputs the data sent to the server, when the connection was closed and when the server is shutting down normally.

On Receive Parameters

  • $fd: If OpenSwoole Server is in TCP mode, the fd of the Client is given. If the OpenSwoole Server is in UDP mode, it's the value calculated based on Client IP.

  • $reactorId: If the OpenSwoole Server is in TCP mode, it's the ID of reactor thread. If the OpenSwoole Server is in UDP mode, it's the value calculated based on Client PORT.

  • $data: The data received from the client side. If there is no TCP protocol configuration, the max length of data that worker process could receive is 64KB.

Multi-port Monitoring

With a OpenSwoole server it is possible to setup multi-port listening so you can listen on more than one incoming port, this is useful when you run a HTTP and HTTPS server, you can listen on port 80 and 443 with the same server for example.

So, taking in the normal server example, lets say we are running the main server on port 9501 but we also want to listen on 9502, we can do the following:

<?php
$server = new OpenSwoole\Http\Server("127.0.0.1", 9501);

// Main server setup would be here...

$port2 = $server->listen('127.0.0.1', 9502, OpenSwoole\Constant::SOCK_TCP);

$port2->on('Receive', function(OpenSwoole\Server $server, $fd, $reactorId, $data)
{
    echo "[#".$server->worker_id."]\tClient[$fd]: $data\n";
});

The example above shows us that we can use the same server process (master server) but listen on an additional port at 9502. From calling $server->listen we are able to setup the on Receive event callback for port 2, allowing us to handle incoming data differently based on each port the server is listening on.

The new server port will process its requests within its own Receive event and won't trigger the main servers event, the new port that is being listened on will be running under the main server, so they will both inherit the same server configuration and be using the HTTP protocol. However, if you call the set() method again on the second port server, you may change the server configuration.

Last updated on September 20, 2022