Рубрики
Uncategorized

(1) Как реализовать единый процесс блокировки сетевого сервера

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

Резюме

Чтобы лучше понять сетевое программирование и написать высокопроизводительный сервис, нам нужно потратить некоторое время, чтобы понять весь процесс обработки сервером клиента и понять некоторые ключевые термины. Первоначально мы хотели добавить некоторые базовые теоретические знания в эту статью, беспокоясь, что слишком долгое чтение не способствует чтению, поэтому мы переиздадим некоторые базовые знания позже, а затем перейдем к основной теме.

теория

В этой статье в основном представлены основные этапы реализации сетевого сервера, и код будет повторен один раз на практике.

Первый шаг

Нам нужно создать сокет , привязать порт сервера и прослушивать порт. В PHP мы можем использовать функцию сервера потоковых сокетов для выполнения вышеуказанных трех шагов.

Второй шаг

Войдите в цикл while, заблокируйте операцию принятия и дождитесь ввода клиентского соединения. В это время программа будет переходить в спящий режим до тех пор, пока новый клиент не начнет подключаться к серверу, и операционная система не разбудит процесс. Функция accept возвращает сокет клиентского подключения

Третий шаг

Используя бесплатное объявление для чтения данных в сокете клиента и получения данных, серверная программа обрабатывает их, а затем использует fwrite для отправки ответа клиенту. Служба с длительным подключением будет продолжать взаимодействовать с клиентом, в то время как служба с коротким подключением, как правило, закроется после получения ответа.

практика

Здесь мы используем код для реализации следующего базового процесса. Прежде чем мы начнем писать код, мы представим несколько функций PHP, которые могут быть использованы в нашем коде для вашего понимания.

функция

stream_socket_server stream_socket_accept call_user_func is_callable fread

Нажмите на функцию для использования

Код

Говори меньше глупостей и иди вперед~

php
 class Worker{
     //Monitor socket
     protected $socket = NULL;
     //Connection event callback
     public $onConnect = NULL;
     //Receive message event callback
     public $onMessage = NULL;
     public function __construct($socket_address) {

     }

     public function run(){

     }
 }



$worker = new Worker('tcp://0.0.0.0:9810');
//A connection event callback was registered in advance
$worker->onConnect = function ($data) {
    Echo 'new connection comes', $data, php_eol;
};
//A receive message event callback is registered in advance
$worker->onMessage = function ($conn, $message) {
};
$worker->run();

Согласно предыдущему процессу, нам нужно отслеживать порт + адрес

public function __construct($socket_address) {
         //Listening address + port
         $this->socket=stream_socket_server($socket_address);
     }

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

public function run(){
        While (true) {// loop listening
         $client = stream_socket_accept ($this - > socket); // blocking listening on the server
        }
     }

Когда новое соединение вступает в процесс пробуждения и запускается обратный вызов события подключения

public function run(){
        While (true) {// loop listening
         $client = stream_socket_accept ($this - > socket); // blocking listening on the server
         If (! Empty ($client) & & is {// socket connection succeeded and is our callback
             //Callback of the connection that triggered the event
             call_user_func($this->onConnect,$client);
         }
        }
     }

Обратный вызов соединения здесь фактически запускает следующий код, который подготовил библиотеку классов

$worker->onConnect = function ($data) {
    Echo 'connection event:' $data, php_eol;
};

При успешном подключении содержимое клиента получается с помощью бесплатного, и запускается событие получения сообщения

public function run(){
      While (true) {// loop listening
         $client = stream_socket_accept ($this - > socket); // blocking listening on the server
         If (! Empty ($client) & & is {// socket connection succeeded and is our callback
             //Callback of the connection that triggered the event
             call_user_func($this->onConnect,$client);
         }
         //Read client content from connection
         $buffer = free ($client, 65535); // parameter 2: the maximum number of bytes read in the buffer
         //Data is read normally. Trigger message receiving event to respond
         if(!empty($buffer) && is_callable($this->onMessage)){
             //Message receive event for trigger time
             Call_user_func ($this - > onmessage, $this, $client, $buffer); // pass it to the current object, current connection and received message in the received message event
         }
       }
     }

Здесь в основном завершен базовый прием сетевых услуг, и также необходим ответ на запрос. Возьмем в качестве примера HTTP-запрос, здесь инкапсулирован метод HTTP-ответа (http://127.0.0.1:9810)

 class Worker{
    ...
    ...
    ...
     public function  send($conn,$content){
         $http_resonse = "HTTP/1.1 200 OK\r\n";
         $http_resonse .= "Content-Type: text/html;charset=UTF-8\r\n";
         $http_resonse .= "Connection: keep-alive\r\n";
         $http_resonse .= "Server: php socket server\r\n";
         $http_resonse .= "Content-length: ".strlen($content)."\r\n\r\n";
         $http_resonse .= $content;
         fwrite($conn, $http_resonse);
     }
 }

Отвечать на HTTP-запросы при срабатывании события получения сообщения

$worker->onMessage = function ($server,$conn, $message) {
    Echo 'from client message:', $message, php_eol;
    $server - > send ($Conn, 'from server message');
};

Это конец ~, полный код через поезд

недостаток

Одновременно может быть обработано только одно соединение. Одновременная обработка нескольких соединений не поддерживается