100多行PHP代碼實現(xiàn)socks5代理服務(wù)器[2]
更新時間:2016年05月05日 08:47:58 作者:秣馬兒
這篇文章主要介紹了100多行PHP代碼實現(xiàn)socks5代理服務(wù)器,需要的朋友可以參考下
100多行PHP代碼實現(xiàn)socks5代理服務(wù)器,這次是使用swoole純異步來寫,使用狀態(tài)機來處理數(shù)據(jù)。目前用它訪問開源中國木有壓力,但訪問網(wǎng)易新聞就壓力山大。我發(fā)現(xiàn)我用別的語言寫得代理,訪問網(wǎng)易新聞都壓力大。嘎嘎,學(xué)藝不精。
對swoole理解不深,不知道怎么處理socket shutdown只關(guān)閉讀/寫這樣,還有就是連接超時,讀寫超時這種怎么處理。在網(wǎng)上看到作者說要用定時器,感覺好麻煩,所以,這次的代理,雖然個人用,一般不會有什么問題,但離產(chǎn)品級的代理,還有段路要走。
如果要利用多核,就使用process模式,設(shè)置worker個數(shù)為cpu數(shù)量即可。
對swoole理解不深,不知道怎么處理socket shutdown只關(guān)閉讀/寫這樣,還有就是連接超時,讀寫超時這種怎么處理。在網(wǎng)上看到作者說要用定時器,感覺好麻煩,所以,這次的代理,雖然個人用,一般不會有什么問題,但離產(chǎn)品級的代理,還有段路要走。
如果要利用多核,就使用process模式,設(shè)置worker個數(shù)為cpu數(shù)量即可。
<?php class 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, 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_nodelay' => 1, 'log_file' => 'socks5_server.log', ]); $server->on('connect', [$this, 'onConnect']); $server->on('receive', [$this, 'onReceive']); $server->on('close', [$this, 'onClose']); $server->start(); } public function onConnect($server, $fd, $fromID) { $this->clients[$fd] = new Client(); } 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 '協(xié)議不正確:' . $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 '不支持的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 連接不上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 當(dāng)host為空時的處理。貌似不存在的域名都解析成了本機的外網(wǎng)ip,奇怪 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();
您可能感興趣的文章:
- 拋棄 PHP 代價太高
- 100行PHP代碼實現(xiàn)socks5代理服務(wù)器
- win7下搭建nginx+php的開發(fā)環(huán)境
- PHP.vs.JAVA
- java解析php函數(shù)json_encode unicode 編碼問題
- wdcp添加tomcat,同時支持php和java教程
- java URL 獲取PHP JSON 數(shù)據(jù)
- PHPExcel筆記, mpdf導(dǎo)出
- php面向?qū)ο笾祮卫J?/a>
- PHP中的.htaccess偽靜態(tài)文件
- Centos安裝php高版本
- 微信公眾平臺DEMO(PHP)
- win10環(huán)境PHP 7 安裝配置【教程】
相關(guān)文章
laravel 解決強制跳轉(zhuǎn) https的問題
今天小編就為大家分享一篇laravel 解決強制跳轉(zhuǎn) https的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-10-10laravel validate 設(shè)置為中文的例子(驗證提示為中文)
今天小編就為大家分享一篇laravel validate 設(shè)置為中文的例子(驗證提示為中文),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-09-09基于php socket(fsockopen)的應(yīng)用實例分析
本篇文章是對php socket(fsockopen)的應(yīng)用實例進行了詳細的分析介紹,需要的朋友參考下2013-06-06