使用swoole扩展写的PHP全异步代理服务器

    本文地址:http://www.tongxinmao.com/Article/Detail/id/59

    客户端socket连接到ProxyServer后,创建一个socket连接到后端Server。并监听后端Server的回包。 客户端向ProxyServer发送请求包,proxy服务器会透明地将此包发往后端Server。

     

    当后端Server返回包时,找到对应的客户端socket,向此socket发送回应的数据包。

    此程序将swoole扩展提供的Server和Client结合在一起使用, ProxyServer对客户端连接来说是服务器端,但对backend服务器来说是客户端。

     

    所有网络IO都是基于epoll事件循环,全异步非阻塞的。性能非常高。 长连接可以达到 10万qps的处理能力。

     

    这里对后端Server和客户端之间使用了1对1的模式,可以改进为n对1连接池的模式,节约backend Server的TCP连接数量。当onReceve收到客户端请求时,将客户端连接与backend连接绑定。返回响应数据后解除绑定,使连接可供下一个客户端使用。

    <?php
    class ProxyServer
    {
        protected $clients;
        protected $backends;
        protected $serv;
    
            function run()
            {
                    $serv = swoole_server_create("127.0.0.1", 9509);
                    swoole_server_set($serv, array(
                            'timeout' => 1,  //select and epoll_wait timeout.
                            'poll_thread_num' => 1, //reactor thread num
                            'worker_num' => 1, //reactor thread num
                            'backlog' => 128,   //listen backlog
                            'max_conn' => 10000,
                            'dispatch_mode' => 2,
                            //'open_tcp_keepalive' => 1,
                            'log_file' => '/tmp/swoole.log', //swoole error log
                    ));
                    swoole_server_handler($serv, 'onWorkerStart', array($this, 'onStart'));
                    swoole_server_handler($serv, 'onConnect',  array($this, 'onConnect'));
                    swoole_server_handler($serv, 'onReceive',  array($this, 'onReceive'));
                    swoole_server_handler($serv, 'onClose',   array($this, 'onClose'));
                    swoole_server_handler($serv, 'onWorkerStop',  array($this, 'onShutdown'));
                    //swoole_server_addtimer($serv, 2);
                    #swoole_server_addtimer($serv, 10);
                    swoole_server_start($serv);
            }
            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)
        {
            //backend
            if(isset($this->clients[$fd]))
            {
                $backend_client = $this->clients[$fd]['socket'];
                unset($this->clients[$fd]);
                $backend_client->close();
                unset($this->backends[$backend_client->sock]);
                echo "client close\n";
            }
        }
    
        function onConnect($serv, $fd, $from_id)
        {
            $socket = new swoole_client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_ASYNC);
            echo microtime().": Client[$fd] backend-sock[{$socket->sock}]: Connect.\n";
            $this->backends[$socket->sock] = array(
                'client_fd' => $fd,
                'socket' => $socket,
            );
            $this->clients[$fd] = array(
                'socket' => $socket,
            );
            $socket->on('connect', function($socket){
                echo "connect to backend server success\n";
            });
            $socket->on('error', function($socket){
                echo "connect to backend server fail\n";
            });
            $socket->on('receive', function($socket){
                swoole_server_send($this->serv, $this->backends[$socket->sock]['client_fd'], $socket->recv());
            });
            $socket->connect('127.0.0.1', 9501, 0.2);
        }
    
        function onReceive($serv, $fd, $from_id, $data)
        {
            echo microtime().": client receive\n";
            $backend_socket = $this->clients[$fd]['socket'];
            $backend_socket->send($data);
            echo microtime().": send to backend\n";
            echo str_repeat('-', 100)."\n";
        }
    }
    
    $serv = new ProxyServer();
    $serv->run();


    上一篇:七个面向对象设计原则和24个设计模式(23个GoF设计模式 + 简单工厂模式)
    下一篇:基于SWOOLE 的TCP客户端服务器