100多行PHP代碼實現(xiàn)socks5代理服務(wù)器[2]
來源:易賢網(wǎng) 閱讀:1096 次 日期:2016-08-24 16:10:56
溫馨提示:易賢網(wǎng)小編為您整理了“100多行PHP代碼實現(xiàn)socks5代理服務(wù)器[2]”,方便廣大網(wǎng)友查閱!

100多行PHP代碼實現(xiàn)socks5代理服務(wù)器,這次是使用swoole純異步來寫,使用狀態(tài)機來處理數(shù)據(jù)。目前用它訪問開源中國木有壓力,但訪問網(wǎng)易新聞就壓力山大。我發(fā)現(xiàn)我用別的語言寫得代理,訪問網(wǎng)易新聞都壓力大。嘎嘎,學藝不精。

對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 當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();

更多信息請查看網(wǎng)絡(luò)編程
易賢網(wǎng)手機網(wǎng)站地址:100多行PHP代碼實現(xiàn)socks5代理服務(wù)器[2]
關(guān)于我們 | 聯(lián)系我們 | 人才招聘 | 網(wǎng)站聲明 | 網(wǎng)站幫助 | 非正式的簡要咨詢 | 簡要咨詢須知 | 加入群交流 | 手機站點 | 投訴建議
工業(yè)和信息化部備案號:滇ICP備2023014141號-1 云南省教育廳備案號:云教ICP備0901021 滇公網(wǎng)安備53010202001879號 人力資源服務(wù)許可證:(云)人服證字(2023)第0102001523號
聯(lián)系電話:0871-65317125(9:00—18:00) 獲取招聘考試信息及咨詢關(guān)注公眾號:hfpxwx
咨詢QQ:526150442(9:00—18:00)版權(quán)所有:易賢網(wǎng)