Автор оригинала: 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/”