当前位置:首页 > PHP教程 > php高级应用 > 列表

100多行PHP代码实现socks5代理服务器[2]

发布:smiling 来源: PHP粉丝网  添加日期:2021-08-01 14:24:42 浏览: 评论:0 

100多行PHP代码实现socks5代理服务器,这次是使用swoole纯异步来写,使用状态机来处理数据。目前用它访问开源中国木有压力,但访问网易新闻就压力山大,我发现我用别的语言写得代理,访问网易新闻都压力大,嘎嘎,学艺不精。

对swoole理解不深,不知道怎么处理socket shutdown只关闭读/写这样,还有就是连接超时,读写超时这种怎么处理。在网上看到作者说要用定时器,感觉好麻烦,所以,这次的代理,虽然个人用,一般不会有什么问题,但离产品级的代理,还有段路要走。

如果要利用多核,就使用process模式,设置worker个数为cpu数量即可。

  1. <?php 
  2. class Client 
  3.  public $connected = true; 
  4.  public $data = ''
  5.  public $remote = null; 
  6.  public $status = 0; 
  7. class Server 
  8.  public $clients = []; 
  9.  public function start() 
  10.  { 
  11.   $server = new swoole_server('0.0.0.0', 8388, SWOOLE_BASE, SWOOLE_SOCK_TCP); 
  12.   $server->set([ 
  13.    'max_conn' => 1000,  
  14.    'daemonize' => 1, 
  15.    'reactor_num' => 1, 
  16.    'worker_num' => 1, 
  17.    'dispatch_mode' => 2, 
  18.    'buffer_output_size' => 128 * 1024 * 1024, 
  19.    'open_cpu_affinity' => 1, 
  20.    'open_tcp_nodelay' => 1, 
  21.    'log_file' => 'socks5_server.log'
  22.   ]); 
  23.   $server->on('connect', [$this'onConnect']); 
  24.   $server->on('receive', [$this'onReceive']); 
  25.   $server->on('close', [$this'onClose']); 
  26.   $server->start(); 
  27.  } 
  28.  public function onConnect($server$fd$fromID
  29.  { 
  30.   $this->clients[$fd] = new Client(); 
  31.  } 
  32.  public function onReceive($server$fd$fromID$data
  33.  { 
  34.   ($this->clients[$fd])->data .= $data
  35.   $this->parse($server$fd);  
  36.  } 
  37.  public function onClose($server$fd$fromID
  38.  { 
  39.   $client = $this->clients[$fd]; 
  40.   $client->connected = false; 
  41.  } 
  42.  private function parse($server$fd)  
  43.  { 
  44.   $client = $this->clients[$fd]; 
  45.  
  46.   switch ($client->status) { 
  47.    case 0: { 
  48.     if (strlen($client->data) >= 2) { 
  49.      $request = unpack('c*'substr($client->data, 0, 2)); 
  50.      if ($request[1] !== 0x05) { 
  51.       echo '协议不正确:' . $request[1], PHP_EOL; 
  52.       $server->close($fd); 
  53.       break
  54.      } 
  55.      $nmethods = $request[2]; 
  56.      if (strlen($client->data) >= 2 + $nmethods) { 
  57.       $client->data = substr($client->data, 2 + $nmethods); 
  58.       $server->send($fd"\x05\x00"); 
  59.       $client->status = 1; 
  60.      } 
  61.     } 
  62.    } 
  63.    case 1: { 
  64.     if (strlen($client->data) < 5) 
  65.      break
  66.     $request = unpack('c*'$client->data); 
  67.     $aType = $request[4]; 
  68.     if ($aType === 0x03) { // domain 
  69.      $domainLen = $request[5]; 
  70.      if (strlen($client->data) < 5 + $domainLen + 2) {  
  71.       break;  
  72.      } 
  73.      $domain = substr($client->data, 5, $domainLen); 
  74.      $port = unpack('n'substr($client->data, 5 + $domainLen, 2))[1];  
  75.      $client->data = substr($client->data, 5 + $domainLen + 2); 
  76.     } else if ($aType === 0x01) { // ipv4 
  77.      $domain = long2ip(unpack('N'substr($client->data, 4, 4))[1]); 
  78.      $port = unpack('n'substr($client->data, 8, 2))[1];  
  79.      $client->data = substr($client->data, 10); 
  80.     } else { 
  81.      echo '不支持的atype:' . $aType, PHP_EOL; 
  82.      $server->close($fd); 
  83.      break
  84.     } 
  85.  
  86.     $remote = new swoole_client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_ASYNC); 
  87.     $remote->on('connect'function($cliuse($client$server$fd$remote) { 
  88.      $server->send($fd"\x05\x00\x00\x01\x00\x00\x00\x00\x00\x00"); 
  89.      $client->status = 2; 
  90.      $client->remote = $remote
  91.     }); 
  92.     $remote->on("error"function(swoole_client $cliuse($server$fd) { 
  93.      //$server->send($fd, ""); // todo 连接不上remote 
  94.      echo 'connect to remote error.', PHP_EOL; 
  95.      $server->close($fd); 
  96.     }); 
  97.     $remote->on('receive'function($cli$datause($server$fd$client) { 
  98.      if (!$client->connected) { 
  99.       echo 'connection has been closed.', PHP_EOL; 
  100.       return
  101.      } 
  102.      $server->send($fd$data); 
  103.     }); 
  104.     $remote->on('close'function($cliuse($server$fd$client) { 
  105.      $client->remote = null; 
  106.     }); 
  107.     if ($aType === 0x03) { 
  108.      swoole_async_dns_lookup($domainfunction($host$ipuse($remote$port$server$fd) { 
  109.       //todo 当host为空时的处理。貌似不存在的域名都解析成了本机的外网ip,奇怪 
  110.       if (emptyempty($ip) || emptyempty($host)) { 
  111.        echo "host:{$host}, ip:{$ip}\n"
  112.        $server->close($fd); 
  113.        return
  114.       } 
  115.       $remote->connect($ip$port); 
  116.      }); 
  117.     } else { 
  118.      $remote->connect($domain$port); 
  119.     } 
  120.    } 
  121.    case 2: { 
  122.     if (strlen($client->data) === 0) { 
  123.      break
  124.     } 
  125.     if ($client->remote === null) { 
  126.      echo 'remote connection has been closed.', PHP_EOL; 
  127.      break
  128.     } 
  129.  
  130.     $sendByteCount = $client->remote->send($client->data); 
  131.     if ($sendByteCount === false || $sendByteCount < strlen($client->data)) { 
  132.      echo 'data length:' , strlen($client->data), ' send byte count:'$sendByteCount, PHP_EOL;  
  133.      echo $client->data, PHP_EOL; 
  134.      $server->close($fd);  
  135.     } 
  136.     $client->data = ''
  137.    } 
  138.   } 
  139.  } 
  140.  
  141. (new Server())->start();

Tags: socks5代理服务器

分享到: