More than 100 lines of PHP code to implement SOCKS5 proxy server, this time using Swoole pure asynchronous to write, using the state machine to process data. Currently using it to access open source Chinese wood is stressful, but visit NetEase news on the pressure of Alexander. I found that I write in other languages agent, access to NetEase news are very stressful. Quack, the Apprentice is not fine.
Not deep understanding of swoole, do not know how to handle the socket shutdown only close read/write 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 the agent, although the personal use, generally will not have any problems, but the agent from the product level, there are a section of the road to go.
If you want to take advantage of multi-core, use process mode, set the number of worker as the number of CPUs.
<?php class Client {public $connected = true;
Public $data = ';
public $remote = null;
Public $status = 0;
Class Server {public $clients = [];
The public Function start () {$server = new Swoole_server (' 0.0.0.0 ', 8388, Swoole_base, swoole_sock_tcp);
$server->set ([' Max_conn ' => 1000, ' daemonize ' => 1, ' Reactor_num ' => 1, ' Worker_num ' => 1, ' Dispatch_mode ' => 2, ' buffer_output_size ' => 128 * 1024 * 1024, ' open_cpu_affinity ' => 1, ' Open_tcp_no
Delay ' => 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 ();
The Public function onreceive ($server, $FD, $fromID, $data) {($this->clients[$fd])->data. = $data;
$this->parse ($server, $FD); } 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
($client->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 ' Unsupported 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\x0
1\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 connection not 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 processing when host is empty.
Seemingly nonexistent domain names are resolved to 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 = '; ->start ()}}} (new Server ());