More than 100 lines of PHP code implemented SOCKS5 Proxy server, this time using Swoole pure asynchronous to write, using state machine to process data. Currently using it to access open source Chinese wood has pressure, but visit NetEase news on the pressure Alexander. I found that I use other languages to write agents, access to NetEase news are pressure. Quack, the Apprentice is not fine.
To swoole understand not deep, do not know how to deal with socket shutdown only read/write down So, there is the connection timeout, read and write timeout this how to deal with. On the Internet to see the author said to use the timer, feel good trouble, so, this time agent, although personal use, generally will not have any problems, but from the product-level agent, there is a section of road to go.
If you want to take advantage of multicore, use process mode and set the number of workers to be CPU.
<?phpclass client{Public $connected = true, public $data = ", public $remote = null, public $status = 0;} Class server{public $clients = []; public function Start () {$server = new Swoole_server (' 0.0.0.0 ', 8388, Swoole_base, S WOOLE_SOCK_TCP); $server->set ([' max_conn ' = +, ' daemonize ' + 1, ' reactor_num ' = + 1, ' worker_num ' = 1, ' Dis Patch_mode ' + 2, ' buffer_output_size ' = + * 1024x768, ' open_cpu_affinity ' + 1, ' open_tcp_nodelay ' = > 1, ' log_file ' = ' socks5_server.log ',]); $server->on (' Connect ', [$this, ' onConnect ']); $server->on (' Receive ', [$this, ' onreceive ']); $server->on (' Close ', [$this, ' onClose ']); $server->start (); The Public Function OnConnect ($server, $FD, $fromID) {$this->clients[$fd] = new Client (), and public function onreceive ($ Server, $FD, $fromID, $data) {($this->clients[$fd])->data. = $data; $this->parse ($server, $FD); The Public Function onClose ($server, $FD, $fromID) {$client = $this->clients[$FD]; $client->connected = false; } Private Function Parse ($server, $fd) {$client = $this->clients[$FD]; Switch ($client->status) {case 0: {if (strlen ($client->data) >= 2) {$request = unpack (' c* ', substr ($c Lient->data, 0, 2)); if ($request [1]!== 0x05) {echo ' protocol is incorrect: '. $request [1], php_eol; $server->close ($FD); Break } $nmethods = $request [2]; if (strlen ($client->data) >= 2 + $nmethods) {$client->data = substr ($client->data, 2 + $nmethods); $server->send ($FD, "\x05\x00"); $client->status = 1; }}} Case 1: {if (strlen ($client->data) < 5) break; $request = Unpack (' c* ', $client->data); $aType = $request [4]; if ($aType = = = 0x03) {//Domain $domainLen = $request [5]; if (strlen ($client->data) < 5 + $domainLen + 2) {break; } $domain = substr ($client->data, 5, $domainLen); $port = Unpack (' N', substr ($client->data, 5 + $domainLen, 2)) [1]; $client->data = substr ($client->data, 5 + $domainLen + 2); } else if ($aType = = = 0x01) {//IPv4 $domain = Long2ip (Unpack (' N ', substr ($client->data, 4, 4)) [1]); $port = Unpack (' n ', substr ($client->data, 8, 2)) [1]; $client->data = substr ($client->data, 10); } else {echo ' does not support atype: '. $aType, Php_eol; $server->close ($FD); Break } $remote = new Swoole_client (swoole_sock_tcp, Swoole_sock_async); $remote->on (' Connect ', function ($CLI) use ($client, $server, $FD, $remote) {$server->send ($fd, "\x05\x00\x00\x01 \x00\x00\x00\x00\x00\x00 "); $client->status = 2; $client->remote = $remote; }); $remote->on ("Error", function (swoole_client $cli) use ($server, $FD) {//$server->send ($FD, ""); Todo is not connected to remote echo ' Connect to remote error. ', Php_eol; $server->close ($FD); }); $remote->on (' Receive ', function ($CLI, $data) use ($Server, $FD, $client) {if (! $client->connected) {echo ' connection has been closed. ', Php_eol; Return } $server->send ($FD, $data); }); $remote->on (' Close ', function ($CLI) use ($server, $FD, $client) {$client->remote = null; }); if ($aType = = = 0x03) {swoole_async_dns_lookup ($domain, function ($host, $IP) use ($remote, $port, $server, $FD) { Todo when host is empty. Seemingly non-existent domain names are parsed into the local network IP, strange if (empty ($IP) | | empty ($host)) {echo "host:{$host}, ip:{$ip}\n"; $server->close ($FD); Return } $remote->connect ($ip, $port); }); } else {$remote->connect ($domain, $port); }} Case 2: {if (strlen ($client->data) = = = 0) {break; } if ($client->remote = = = null) {echo ' Remote connection has been closed. ', Php_eol; Break } $sendByteCount = $client->remote->send ($client->data); if ($sendByteCount = = = False | | $sendByteCount < strlen ($client->data) {echo ' Data length: ', strlen ($client->data), ' Send byte Count: ', $sendByteCount, Php_eol; Echo $client->data, Php_eol; $server->close ($FD); } $client->data = "; }}} (new Server ())->start ();