Рубрики
Uncategorized

Применение мультипротокола swool и многопортового

Автор оригинала: David Wong.

Резюме

Это пятая статья об обучении swool: применение мультипротокола swool и мультипорта .

  • Часть 4: применение swool http
  • Часть 3: применение swool websocket
  • Часть 2: применение задачи свула
  • Часть 1: применение таймера свула

В основном обратитесь к официальным двум статьям для реализации демо.

  • Разработка сетевого протокола связи: https://wiki.swoole.com/wiki/
  • Использование многопортового мониторинга: https://wiki.swoole.com/wiki/

Я надеюсь, что благодаря предоставленной мной демонстрации я смогу глубже понять документ.

Разработка сетевого протокола связи

Почему протокол связи?

Официальный: протокол TCP решает проблему повторной передачи порядка и потери пакетов протокола UDP в базовом механизме. Но по сравнению с UDP это приносит новые проблемы. Протокол TCP является потоковым, и пакеты не имеют границ. Приложения, использующие TCP-связь, столкнутся с этими проблемами. Поскольку связь по протоколу TCP является потоковой, при получении большого пакета он может быть разделен на несколько пакетов для отправки. Несколько слоев отправки также могут быть объединены в одну отправку. Для решения этой проблемы необходимы две операции: разделение пакетов и объединение пакетов. Поэтому протокол связи необходимо устанавливать при взаимодействии по сети TCP.

Swool поддерживает два типа пользовательских сетевых протоколов связи: протокол терминатора, фиксированный заголовок пакета + протокол тела пакета.

Протокола терминатора

Сначала посмотрите на эффект отсутствия настройки протокола:

Длина каждого набора данных равна 23, но когда onReceive получает данные, длина каждого полученного набора данных отличается, и пакет не передается на субподряд, как предполагалось.

Затем установите действие протокола терминатора EOF:

Длина каждого набора данных составляет 23. При получении данных в onReceive, каждое полученное значение равно 23. Идеальный.

Основные настройки следующие:

'package_max_length' => '8192',
'open_eof_split'     => true,
'package_eof'        => "\r\n"

Без объяснения причин официальные документы были написаны четко.

Пример кода выглядит следующим образом:

сервер. php

serv = new swoole_server('0.0.0.0', 9501);
        $this->serv->set([
            'worker \ num' = > 2, // start 2 worker processes
            'max'request' = > 4, // max'request is set to 4 times per worker process
            'dispatch [mode' = > 2, // packet distribution policy - fixed mode

            //EOF terminator 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;
        Echo "swoole". 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();

php

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 = "client sends information... \ 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();

Фиксированная головка упаковки + пакетное соглашение

Сначала посмотрите на эффект отсутствия настройки протокола:

Очевидно, что в onReceive получено мало данных.

Давайте посмотрим на эффект настройки протокола:

Основные настройки следующие:

'open_length_check'     => true,
'package_max_length'    => '8192',
'package_length_type'   => 'N',
'package_length_offset' => '0',
'package_body_offset'   => '4',

Без объяснения причин официальные документы были написаны четко.

Пример кода выглядит следующим образом:

Пример кода выглядит следующим образом:

serv = new swoole_server('0.0.0.0', 9501);
        $this->serv->set([
            'worker \ num' = > 2, // start 2 worker processes
            'max'request' = > 4, // max'request is set to 4 times per worker process
            'dispatch [mode' = > 2, // packet distribution policy - fixed mode

            //Fixed package head + package agreement
            '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;
        Echo "swoole". 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();

Пример кода выглядит следующим образом:

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() {
        $MSG = 'information sent by client...';
        $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();

Использование многопортового мониторинга

На приведенном выше рисунке прослушивание портов в примере кода:

  • 9501 onmessage обрабатывает веб-пакеты.
  • 9501 onrequest обрабатывает http.
  • 9502 onReceive обрабатывает TCP.
  • 9503 onPacket обрабатывает UDP.

Не говори много, посмотри на изображения:

Пример кода выглядит следующим образом:

Пример кода выглядит следующим образом:

serv = new swoole_websocket_server("0.0.0.0", 9501);
        $this->serv->set([
            'worker \ num' = > 2, // start 2 worker processes
            'max'request' = > 4, // max'request is set to 4 times per worker process
            'task'worker'num' = > 4, // start 4 task processes
            'dispatch [mode' = > 4, // packet distribution policy - IP allocation
            'daemonize' = > false, // daemons (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 2 worker processes
            'max'request' = > 4, // max'request is set to 4 times per worker process
            'dispatch [mode' = > 2, // packet distribution policy - fixed mode

            //Fixed package head + package agreement
            '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 2 worker processes
            'max'request' = > 4, // max'request is set 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;
        Echo "swoole". 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); // maximum length cannot 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 > Hello 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();

Коды четырех клиентских подключений следующие:

1. 9501 onmessage обрабатывает websocket. Вы можете обратиться к коду в приложении swool websocket.

2. 9501 onrequest обрабатывает http. Вы можете обратиться к коду в приложении swool http.

3. 9502 onReceive обрабатывает TCP. Вы можете обратиться к коду в приложении задачи swool.

4. 9503 на пакетах обрабатывает UDP.

Пример кода:

netcat -u 10.211.55.4 9503

Резюме

I. каков сценарий применения многопортового?

Например, для разработки живого веб-сайта прямая трансляция использует один порт, чат обмена мгновенными сообщениями использует один порт.

Например, разработайте службу RPC, используйте порт для передачи данных и используйте порт для статистического интерфейса.

Рекомендуемое чтение

  • Системное объяснение Единый вход единого входа
  • Системное объяснение – Защита веб-безопасности PHP
  • Системное объяснение – Технология кэширования PHP
  • Системное объяснение – Проверка подписи интерфейса PHP
  • Системное объяснение – высокоточная работа PHP с плавающей запятой

Эту статью добро пожаловать переслать, переслать пожалуйста, укажите автора и источник, спасибо!

Оригинал: “https://developpaper.com/application-of-swoole-multi-protocol-and-multi-port/”