最近始终在学习Swoole,刚好有个老我的项目的一小部分(一个脚本)有用到了Tcp 协定,借此机会重构一下。

场景形容:

该脚本的作用用一句话就能够概述:将本地数据源推送给另外一台服务器。

原始的解决形式,不合理的中央有以下几点:

  1. 指标服务器须要凋谢指定端口,这会导致指标服务器向外裸露,不平安。
  2. 如果有多台指标服务器,这会导致频繁须要批改源码,脚本保护起来不不便。

重构

重构须要解决的问题有如下:

  1. 当客户端连贯胜利后,才会向该客户端推送数据。
  2. 当客户端断开连接时,进行向该客户端推送数据。
  3. 容许多个客户端同时连贯。
  4. 因为数据源是不间断的,实践上只有客户端的连贯不被动断开,服务端的数据推送就不会被动进行。

最终应用Swoole 的Tcp + Process 实现了以上需要,外围代码如下:

<?phpuse Swoole\Process;/** * 创立Server 对象,监听本地 9501 端口。 */$server = new Swoole\Server("0.0.0.0", 9501);$workers = [];/** * 监听连贯进入事件 */$server->on("Connect", function ($server, $fd) {    global $workers;        // 创立子过程    $process = new swoole_process(function (swoole_process $worker) use ($server, $fd) {        echo "Client Connect" . PHP_EOL;      // todo 业务逻辑      ...             // 向客户端推送音讯         $server->send($fd, $str);          }, true, 0, false);        // 启动子过程    $pid = $process->start();        array_push($workers, ["pid" => $pid, "fd" => $fd]);});/** * 监听数据接管事件 */$server->on("Receive", function ($server, $fd, $from_id, $data){    $server->send($fd, "Server: " . $data);});/** * 监听连贯敞开事件 */$server->on("Close", function ($server, $fd) {    global $workers;        foreach ($workers as $worker) {      if ($worker['fd'] === $fd){        // 查看子过程是否存在          if (Process::kill($worker['pid'], 0)){              array_shift($worker);              // 通过信号终止子过程              Process::kill($worker['pid'], SIGKILL);          }      }    }    echo "Client Close" . PHP_EOL;});// 启动TCP 服务器$server->start();

其实实现的原理很简略,利用Swoole 的基于事件的 Tcp 异步编程,当有客户端连贯时,就创立一个子过程进行推送数据,但客户端连贯断开时,就通过信号完结该客户端对应的子过程。