Article 81

This is the fifth article on Swoole learning: The application of Swoole multi-protocol and Multi-port.

  • Swoole HTTP application

  • Swoole WebSocket application

  • Swoole Task application

  • Swoole Timer application

An overview of the

The main reference of these two official articles, the implementation of the Demo.

  • Network communication protocol design:

    https://wiki.swoole.com/wiki/page/484.html

  • Use of multi-port listening:

    https://wiki.swoole.com/wiki/page/161.html

I hope I can have a more profound understanding of the document through the Demo I provide.

Network communication protocol design

Why do you need a communication protocol?

Official: THE TCP protocol solves the order and packet loss retransmission problems of UDP protocol on the underlying mechanism. But compared to UDP, this brings a new problem. TCP is streaming, and packets have no boundaries. Applications that communicate using TCP face these challenges. Because TCP communication is streaming, when one large packet is received, it may be split into multiple packets for transmission. Multiple Send layers may also be combined into a single Send. This requires two operations to solve: subcontracting and combining, so TCP network communication needs to set the communication protocol.

Swoole supports two types of custom network communication protocols: EOF termination protocol and fixed header + body protocol.

EOF End protocol

Let’s take a look at the effect of not setting the protocol:

Each piece of data sent was of length 23, but onReceive received data at different lengths each time, and it was not subcontracted in the way it was supposed to be.

Set the EOF terminator protocol:

Each message sent is of length 23, and onReceive receives data every time it receives 23. Perfect.

The main Settings are as follows:


     

    'package_max_length' => '8192',

    'open_eof_split' => true,

    'package_eof' => "\r\n"

Copy the code

Do not explain, the official documents have been written very clear.

The example code is as follows:

server.php


     

    <? php

    class Server

    {

    private $serv;

    public function __construct() {

    $this->serv = new swoole_server('0.0.0.0', 9501);

    $this->serv->set([

    'worker_num' => 2, // Start two worker processes

    'max_request' => 4, // set max_request to 4 times per worker process

    'dispatch_mode' => 2, // Packet distribution policy - fixed mode

    //EOF End protocol

    'package_max_length' => '8192',

    'open_eof_split' => true,

    'package_eof' => "\r\n"

    ]);

    $this->serv->on('Start', [$this, 'onStart']);

    $this->serv->on('Connect', [$this, 'onConnect']);

    $this->serv->on("Receive", [$this, 'onReceive']);

    $this->serv->on("Close", [$this, 'onClose']);

    $this->serv->start();

    }

    public function onStart($serv) {

    echo "#### onStart ####".PHP_EOL;

    SWOOLE_VERSION. "Service started ".PHP_EOL;

    echo "swoole_cpu_num:".swoole_cpu_num().PHP_EOL;

    echo "master_pid: {$serv->master_pid}".PHP_EOL;

    echo "manager_pid: {$serv->manager_pid}".PHP_EOL;

    echo "########".PHP_EOL.PHP_EOL;

    }

    public function onConnect($serv, $fd) {

    echo "#### onConnect ####".PHP_EOL;

    Echo "client :".$fd." connected ".PHP_EOL;

    echo "########".PHP_EOL.PHP_EOL;

    }

    public function onReceive($serv, $fd, $from_id, $data) {

    echo "#### onReceive ####".PHP_EOL;

    var_dump($data);

    }

    public function onClose($serv, $fd) {

    echo "Client Close.".PHP_EOL;

    }

    }

    $server = new Server();

Copy the code

client.php


     

    <? php

    class Client

    {

    private $client;

    public function __construct() {

    $this->client = new swoole_client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_ASYNC);

    $this->client->on('Connect', [$this, 'onConnect']);

    $this->client->on('Close', [$this, 'onClose']);

    $this->client->on('Error', [$this, 'onError']);

    }

    public function connect() {

    if(! $fp = $this - > client - > connect (" 127.0.0.1 ", 9501)) {

    echo "Error: {$fp->errMsg}[{$fp->errCode}]".PHP_EOL;

    return;

    }

    }

    public function onConnect() {

    Fwrite (STDOUT, "send test data (Y or N):");

    swoole_event_add(STDIN, function() {

    $msg = trim(fgets(STDIN));

    if ($msg == 'y') {

    $this->send();

    }

    Fwrite (STDOUT, "send test data (Y or N):");

    });

    }

    public function send() {

    $msg_info = "$msg_info... \r\n";

    $i = 0;

    while ($i < 50) {

    var_dump($msg_info);

    $this->client->send($msg_info);

    $i++;

    }

    }

    public function onClose() {

    echo "Client close connection".PHP_EOL;

    }

    public function onError() {

    }

    }

    $client = new Client();

    $client->connect();

Copy the code

Fixed header + body protocol

Let’s take a look at the effect of not setting the protocol:

Obviously, the data received in onReceive is small.

Now look at the effect of setting the protocol:

The main Settings are as follows:


     

    'open_length_check' => true,

    'package_max_length' => '8192',

    'package_length_type' => 'N',

    'package_length_offset' => '0',

    'package_body_offset' => '4',

Copy the code

Do not explain, the official documents have been written very clear.

The example code is as follows:

server.php


     

    <? php

    class Server

    {

    private $serv;

    public function __construct() {

    $this->serv = new swoole_server('0.0.0.0', 9501);

    $this->serv->set([

    'worker_num' => 2, // Start two worker processes

    'max_request' => 4, // set max_request to 4 times per worker process

    'dispatch_mode' => 2, // Packet distribution policy - fixed mode

    // Fixed header + body protocol

    'open_length_check' => true,

    'package_max_length' => '8192',

    'package_length_type' => 'N',

    'package_length_offset' => '0',

    'package_body_offset' => '4',

    ]);

    $this->serv->on('Start', [$this, 'onStart']);

    $this->serv->on('Connect', [$this, 'onConnect']);

    $this->serv->on("Receive", [$this, 'onReceive']);

    $this->serv->on("Close", [$this, 'onClose']);

    $this->serv->start();

    }

    public function onStart($serv) {

    echo "#### onStart ####".PHP_EOL;

    echo "swoole_cpu_num:".swoole_cpu_num().PHP_EOL;

    SWOOLE_VERSION. "Service started ".PHP_EOL;

    echo "master_pid: {$serv->master_pid}".PHP_EOL;

    echo "manager_pid: {$serv->manager_pid}".PHP_EOL;

    echo "########".PHP_EOL.PHP_EOL;

    }

    public function onConnect($serv, $fd) {

    echo "#### onConnect ####".PHP_EOL;

    Echo "client :".$fd." connected ".PHP_EOL;

    echo "########".PHP_EOL.PHP_EOL;

    }

    public function onReceive($serv, $fd, $from_id, $data) {

    echo "#### onReceive ####".PHP_EOL;

    $length = unpack('N', $data)[1];

    echo "Length:".$length.PHP_EOL;

    $msg = substr($data, -$length);

    echo "Msg:".$msg.PHP_EOL;

    }

    public function onClose($serv, $fd) {

    echo "Client Close.".PHP_EOL;

    }

    }

    $server = new Server();

Copy the code

client.php


     

    <? php

    class Client

    {

    private $client;

    public function __construct() {

    $this->client = new swoole_client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_ASYNC);

    $this->client->on('Connect', [$this, 'onConnect']);

    $this->client->on('Close', [$this, 'onClose']);

    $this->client->on('Error', [$this, 'onError']);

    }

    public function connect() {

    if(! $fp = $this - > client - > connect (" 127.0.0.1 ", 9501, 1)) {

    echo "Error: {$fp->errMsg}[{$fp->errCode}]".PHP_EOL;

    return;

    }

    }

    public function onConnect() {

    Fwrite (STDOUT, "send test data (Y or N):");

    swoole_event_add(STDIN, function() {

    $msg = trim(fgets(STDIN));

    if ($msg == 'y') {

    $this->send();

    }

    Fwrite (STDOUT, "send test data (Y or N):");

    });

    }

    public function send() {

    If ($MSG = $MSG) {if ($MSG = $MSG) { ';

    $msg_info = pack('N', strlen($msg)).$msg;

    $i = 0;

    while ($i < 50) {

    var_dump($msg_info);

    $this->client->send($msg_info);

    $i++;

    }

    }

    public function onClose() {

    echo "Client close connection".PHP_EOL;

    }

    public function onError() {

    }

    }

    $client = new Client();

    $client->connect();

Copy the code

Use of multi-port listening

Above, the port listener in the sample code:

  • 9501 onMessage handles WebSockets.

  • 9501 onRequest handles HTTP.

  • 9502 onReceive processes TCP.

  • 9503 onPacket Processes UDP.

Without further ado, take a look at the renderings:

The example code is as follows:

server.php


     

    <? php

    class Server

    {

    private $serv;

    public function __construct() {

    $this->serv = new swoole_webSocket_server ("0.0.0.0", 9501);

    $this->serv->set([

    'worker_num' => 2, // Start two worker processes

    'max_request' => 4, // set max_request to 4 times per worker process

    'task_worker_num' => 4, // Start four task processes

    'dispatch_mode' => 4, // Packet distribution policy -IP allocation

    'daemonize' => false, // daemon (true/false)

    ]);

    $this->serv->on('Start', [$this, 'onStart']);

    $this->serv->on('Open', [$this, 'onOpen']);

    $this->serv->on("Message", [$this, 'onMessage']);

    $this->serv->on("Request", [$this, 'onRequest']);

    $this->serv->on("Close", [$this, 'onClose']);

    $this->serv->on("Task", [$this, 'onTask']);

    $this->serv->on("Finish", [$this, 'onFinish']);

    // Listen to port 9502

    TCP = $$this - > serv - > listen (" 0.0.0.0 ", 9502, SWOOLE_SOCK_TCP);

    $tcp->set([

    'worker_num' => 2, // Start two worker processes

    'max_request' => 4, // set max_request to 4 times per worker process

    'dispatch_mode' => 2, // Packet distribution policy - fixed mode

    // Fixed header + body protocol

    'open_length_check' => true,

    'package_max_length' => '8192',

    'package_length_type' => 'N',

    'package_length_offset' => '0',

    'package_body_offset' => '4',

    ]);

    $tcp->on("Receive", [$this, 'onReceive']);

    // Listen to port 9503

    $udp = $this - > serv - > listen (" 0.0.0.0 ", 9503, SWOOLE_SOCK_UDP);

    $udp->set([

    'worker_num' => 2, // Start two worker processes

    'max_request' => 4, // set max_request to 4 times per worker process

    'dispatch_mode' => 2, // Packet distribution policy - fixed mode

    ]);

    $udp->on("Packet", [$this, 'onPacket']);

    $this->serv->start();

    }

    public function onStart($serv) {

    echo "#### onStart ####".PHP_EOL;

    SWOOLE_VERSION. "Service started ".PHP_EOL;

    echo "master_pid: {$serv->master_pid}".PHP_EOL;

    echo "manager_pid: {$serv->manager_pid}".PHP_EOL;

    echo "########".PHP_EOL.PHP_EOL;

    }

    public function onOpen($serv, $request) {

    echo "#### onOpen ####".PHP_EOL;

    echo "server: handshake success with fd{$request->fd}".PHP_EOL;

    $serv->task([

    'type' => 'login'

    ]);

    echo "########".PHP_EOL.PHP_EOL;

    }

    public function onTask($serv, $task_id, $from_id, $data) {

    echo "#### onTask ####".PHP_EOL;

    echo "#{$serv->worker_id} onTask: [PID={$serv->worker_pid}]: task_id={$task_id}".PHP_EOL;

    $msg = '';

    switch ($data['type']) {

    case 'login':

    $MSG = 'I'm here... ';

    break;

    case 'speak':

    $msg = $data['msg'];

    break;

    }

    foreach ($serv->connections as $fd) {

    $connectionInfo = $serv->connection_info($fd);

    if (isset($connectionInfo['websocket_status']) && $connectionInfo['websocket_status'] == 3) {

    $serv->push($fd, $msg); // The maximum length shall not exceed 2M

    }

    }

    $serv->finish($data);

    echo "########".PHP_EOL.PHP_EOL;

    }

    public function onFinish($serv,$task_id, $data) {

    echo "#### onFinish ####".PHP_EOL;

    Echo "Task {$task_id} completed ".PHP_EOL;

    echo "########".PHP_EOL.PHP_EOL;

    }

    public function onClose($serv, $fd) {

    echo "#### onClose ####".PHP_EOL;

    echo "client {$fd} closed".PHP_EOL;

    echo "########".PHP_EOL.PHP_EOL;

    }

    public function onMessage($serv, $frame) {

    echo "#### onMessage ####".PHP_EOL;

    echo "receive from fd{$frame->fd}:{$frame->data},opcode:{$frame->opcode},fin:{$frame->finish}".PHP_EOL;

    $serv->task(['type' => 'speak', 'msg' => $frame->data]);

    echo "########".PHP_EOL.PHP_EOL;

    }

    public function onRequest($request, $response) {

    echo "#### onRequest ####".PHP_EOL;

    $response->header("Content-Type", "text/html; charset=utf-8");

    $server = $request->server;

    $path_info = $server['path_info'];

    $request_uri = $server['request_uri'];

    echo "PATH_INFO:".$path_info.PHP_EOL;

    if ($path_info == '/favicon.ico' || $request_uri == '/favicon.ico') {

    return $response->end();

    }

    $HTML = "<h1> Swoole.</h1>";

    $response->end($html);

    }

    public function onReceive($serv, $fd, $from_id, $data) {

    echo "#### onReceive ####".PHP_EOL;

    $length = unpack('N', $data)[1];

    echo "Length:".$length.PHP_EOL;

    $msg = substr($data, -$length);

    echo "Msg:".$msg.PHP_EOL;

    }

    public function onPacket($serv, $data, $clientInfo) {

    echo "#### onPacket ####".PHP_EOL;

    $serv->sendto($clientInfo['address'], $clientInfo['port'], "Server ".$data);

    var_dump($clientInfo);

    }

    }

    $server = new Server();

Copy the code

The code for the 4 client connections is:

1. 9501 onMessage handles WebSocket. Refer to the code in the original article Swoole WebSocket application.

2, 9501 onRequest processing HTTP. Refer to the code in the original article Swoole HTTP application.

3. 9502 onReceive processes TCP. Refer to the code in the original article Swoole Task application.

4, 9503 onPacket processing UDP.

Example code:


     

    Netcat -u 10.211.55.4 9503

Copy the code

summary

I. What is the application scenario of multiple ports?

For example, develop a live streaming site with one port for live streaming and one port for IM chat.

For example, develop an RPC service with one port for data communication and one port for the statistics interface.

Recommended reading

  • Explanation of the system – PHP interface signature verification

  • Explanation of the system – PHP floating point high precision operation

  • System explanation – PHP caching technology

  • System explanation – PHP WEB security defense

  • Explanation of the system – SSO single sign-on

This article is welcome to forward, forward please indicate the author and source, thank you!