swoole / swoole-src

🚀 Coroutine-based concurrency library for PHP
https://www.swoole.com
Apache License 2.0
18.33k stars 3.16k forks source link

Example script in swoole github is broken. How can the proxy server script be updated? #5178

Open AlwaysCompile opened 8 months ago

AlwaysCompile commented 8 months ago

Please answer these questions before submitting your issue.

  1. What did you do? If possible, provide a simple script for reproducing the error.

The example script is broken: https://github.com/swoole/proxy-server/blob/master/tcp-proxy.php

  1. What did you expect to see?

The working script

  1. What did you see instead?

It is broken because swoole no longer supports callbacks for clients? The "on()" method cannot be found. Swoole also does not seem to provide a way to pipe data and events between sockets, so there is not a way to get data and relay it back to the client as a proxy server should do.

How can the example script be made working again with the new coroutine system?

NathanFreeman commented 8 months ago
<?php
class ProxyServer
{
    protected $frontends;
    protected $backends;
    /**
     * @var swoole_server
     */
    protected $serv;
    protected $index = 0;
    protected $mode = SWOOLE_BASE;
    protected $backendServer = array('host' => '127.0.0.1', 'port' => '80');

    function run()
    {
        $serv = new Swoole\Server("127.0.0.1", 9509, $this->mode);
        $serv->set(array(
            'worker_num' => 8, //worker process num
            //'backlog' => 128, //listen backlog
            //'open_tcp_keepalive' => 1,
            //'log_file' => '/tmp/swoole.log', //swoole error log
        ));
        $serv->on('WorkerStart', array($this, 'onStart'));
        $serv->on('Receive', array($this, 'onReceive'));
        $serv->on('Close', array($this, 'onClose'));
        $serv->on('WorkerStop', array($this, 'onShutdown'));
        $serv->start();
    }

    function onStart($serv)
    {
        $this->serv = $serv;
        echo "Server: start.Swoole version is [" . SWOOLE_VERSION . "]\n";
    }

    function onShutdown($serv)
    {
        echo "Server: onShutdown\n";
    }

    function onClose($serv, $fd, $from_id)
    {
        if (isset($this->frontends[$fd]))
        {
            $backend_socket = $this->frontends[$fd];
            $backend_socket->closing = true;
            $backend_socket->close();
            unset($this->backends[$backend_socket->sock]);
            unset($this->frontends[$fd]);
        }
        echo "onClose: frontend[$fd]\n";
    }

    function onReceive($serv, $fd, $from_id, $data)
    {
        if (!isset($this->frontends[$fd]))
        {
            $socket = new swoole_client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_ASYNC);
            $socket->closing = false;
            $socket->on('connect', function (swoole_client $socket) use ($data)
            {
                $socket->send($data);
            });

            $socket->on('error', function (swoole_client $socket) use ($fd)
            {
                echo "ERROR: connect to backend server failed\n";
                $this->serv->send($fd, "backend server not connected. please try reconnect.");
                $this->serv->close($fd);
            });

            $socket->on('close', function (swoole_client $socket) use ($fd)
            {
                echo "onClose: backend[{$socket->sock}]\n";
                unset($this->backends[$socket->sock]);
                unset($this->frontends[$fd]);
                if (!$socket->closing)
                {
                    $this->serv->close($fd);
                }
            });

            $socket->on('receive', function (swoole_client $socket, $_data) use ($fd)
            {
                $this->serv->send($fd, $_data);
            });

            if ($socket->connect($this->backendServer['host'], $this->backendServer['port']))
            {
                $this->backends[$socket->sock] = $fd;
                $this->frontends[$fd] = $socket;
            }
            else
            {
                echo "ERROR: cannot connect to backend server.\n";
                $this->serv->send($fd, "backend server not connected. please try reconnect.");
                $this->serv->close($fd);
            }
        }
        else
        {
            /**
             * @var $socket swoole_client
             */
            $socket = $this->frontends[$fd];
            $socket->send($data);
        }
    }
}

$serv = new ProxyServer();
$serv->run();
AlwaysCompile commented 8 months ago

Hello @NathanFreeman that is still using the same broken script. Swoole no longer supports clients with SWOOLE_SOCK_ASYNC. You can see this here: https://github.com/swoole/ext-async

Does swoole no longer support this functionality in the latest versions or is there a way to perform the proxy using supported methods? It looks like swoole has removed async client support and only supports coroutines. Can routines be used to make the proxy script work as intended?