Snoole TCP learning

Time:2021-4-19

Recently, I have been learning about spool. Just a small part of an old project (a script) has used TCP protocol. Take this opportunity to refactor it.

Scene Description:

The role of the script can be summarized in one sentence: push the local data source to another server.

There are some unreasonable aspects in the original way

  1. The target server needs to open the specified port, which will cause the target server to be exposed and unsafe.
  2. If there are multiple target servers, it will lead to frequent source code modification and inconvenient script maintenance.

restructure

The problems to be solved in refactoring are as follows:

  1. When the client is connected successfully, the data will be pushed to the client.
  2. When the client is disconnected, stop pushing data to the client.
  3. Allow multiple clients to connect at the same time.
  4. Because the data source is uninterrupted, in theory, as long as the client does not actively disconnect, the server will not actively stop the data push.

Finally, the above requirements are realized by using TCP + process of spool. The core code is as follows:

<?php
use Swoole\Process;

/**
 *Create a server object and listen to the local port 9501.
 */
$server = new Swoole\Server("0.0.0.0", 9501);

$workers = [];

/**
 *Listen for connection entry events
 */
$server->on("Connect", function ($server, $fd) {
    global $workers;
    
    //Create child process
    $process = new swoole_process(function (swoole_process $worker) use ($server, $fd) {
        echo "Client Connect" . PHP_EOL;

      //Todo business logic
      ...
       
      //Push message to client   
      $server->send($fd, $str);
      
    }, true, 0, false);
    
    //Start child process
    $pid = $process->start();
    
    array_push($workers, ["pid" => $pid, "fd" => $fd]);
});

/**
 *Monitoring data receiving events
 */
$server->on("Receive", function ($server, $fd, $from_id, $data){
    $server->send($fd, "Server: " . $data);
});

/**
 *Listen for connection closing events
 */
$server->on("Close", function ($server, $fd) {
    global $workers;
    
    foreach ($workers as $worker) {
      if ($worker['fd'] === $fd){
        //Check whether the child process exists
          if (Process::kill($worker['pid'], 0)){
              array_shift($worker);
              //Terminate child process by signal
              Process::kill($worker['pid'], SIGKILL);
          }
      }
    }
    echo "Client Close" . PHP_EOL;
});

//Start TCP server
$server->start();

In fact, the principle of implementation is very simple, using the event based TCP asynchronous programming of spool, when there is a client connection, a sub process is created to push data, but when the client connection is broken, the corresponding sub process of the client is terminated by signal.

Recommended Today

Envoy announced alpha version of native support for windows

Author: sunjay Bhatia Since 2016, porting envoy to the windows platform has been an important part of the projectOne of the goalsToday, we are excited to announce the alpha version of envoy’s windows native support. The contributor community has been working hard to bring the rich features of envoy to windows, which is another step […]