class="php">客户端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();
?