最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

100行PHP代碼實現(xiàn)socks5代理服務(wù)器

 更新時間:2016年04月28日 10:17:58   作者:秣馬兒  
這個例子說了in the real world, do something here to ensure clients not running are destroyed 但是,如何把不再運行的連接銷毀卻沒有講。恩。我試了把$clients放到一個類里,把類傳給線程類,然后在線程類要結(jié)束時把$clients里對應(yīng)的連接給unset掉,無果。

前兩天在B站上看到一個小伙紙100元組裝個電腦打LOL畫質(zhì)流暢,突發(fā)奇想100行代碼能(簡單)實現(xiàn)個啥好玩的。我主要是做php開發(fā)的,于是就有了本文。

當(dāng)然,由于php(不算swoole擴展)本身不擅長做網(wǎng)絡(luò)服務(wù)端編程,所以這個代理,只是個玩具,離日常使用有點距離。如果想使用穩(wěn)定可靠的加密(所以能禾斗學(xué)上網(wǎng))代理,可以用這個:https://github.com/momaer/asocks-go也是100來行代碼使用go實現(xiàn)。

寫的過程中發(fā)現(xiàn)php多線程還是難的。比如我開始想每個連接新建一個線程。但這個線程得保存起來(比如保存到數(shù)組),比如官方例子中的這個:https://github.com/krakjoe/pthreads/blob/master/examples/SocketServer.php 要放到$clients這個數(shù)組里,不然,你試試(curl -L一個要301的地址)就知道出現(xiàn)什么情況了。

這個例子說了in the real world, do something here to ensure clients not running are destroyed 但是,如何把不再運行的連接銷毀卻沒有講。恩。我試了把$clients放到一個類里,把類傳給線程類,然后在線程類要結(jié)束時把$clients里對應(yīng)的連接給unset掉,無果。

那,以下就是使用線程池來實現(xiàn)的代理,按道理講,退出時池要shutdown(),監(jiān)聽socket也要shutdown的,但百行代碼,就不勉強了,隨著ctrl + c,就讓操作系統(tǒng)來回收資源吧。

php不擅長網(wǎng)絡(luò)編程體現(xiàn)在哪里呢?首先我用的是stream_socket_XXX相關(guān)的函數(shù),為啥不用socket擴展呢?因為socket擴展有問題,參見:https://github.com/krakjoe/pthreads/issues/581 而stream_set_timeout對stream_socket_recvfrom這些高級操作,不起作用,參見:http://php.net/manual/en/function.stream-set-timeout.php 而這些,在寫代理時都需要考慮的。比如連接遠程目標(biāo)服務(wù)器時,沒有超時控制,很容易就線程池跑滿了。

測試的話,使用curl即可,對了,目前只支持遠程dns解析,為啥呢?因為這個玩具后期可是要實現(xiàn)禾斗學(xué)上網(wǎng)的喲: curl --socks5-hostname 127.0.0.1:1080 http://ip.cn

Class Pipe extends Threaded
{
  private $client;
  private $remote;
  public function __construct($client, $remote) 
  {
    $this->client = $client;
    $this->remote = $remote; 
  }
  public function run()
  {
    for ( ; ; ) {
        $data = stream_socket_recvfrom($this->client, 4096);
        if ($data === false || strlen($data) === 0) {
          break;
        } 
        $sendBytes = stream_socket_sendto($this->remote, $data);
        if ($sendBytes <= 0) {
          break;
        }
    }
    stream_socket_shutdown($this->client, STREAM_SHUT_RD);
    stream_socket_shutdown($this->remote, STREAM_SHUT_WR);
  }
}

Class Client extends Threaded
{
  public $fd;
  public function __construct($fd)
  {
    $this->fd = $fd; 
  }

  public function run()
  {
    $data = stream_socket_recvfrom($this->fd, 2);
    $data = unpack('c*', $data);
    if ($data[1] !== 0x05) {
      stream_socket_shutdown($this->fd, STREAM_SHUT_RDWR);
      echo '協(xié)議不正確.', PHP_EOL;
      return;
    }
    $nmethods = $data[2];
    $data = stream_socket_recvfrom($this->fd, $nmethods);
    stream_socket_sendto($this->fd, "\x05\x00");
    $data = stream_socket_recvfrom($this->fd, 4);
    $data = unpack('c*', $data);
    $addressType = $data[4];
    if ($addressType === 0x03) { // domain
      $domainLength = unpack('c', stream_socket_recvfrom($this->fd, 1))[1];
      $data = stream_socket_recvfrom($this->fd, $domainLength + 2);
      $domain = substr($data, 0, $domainLength);
      $port = unpack("n", substr($data, -2))[1];
    } else {
      stream_socket_shutdown($this->fd, STREAM_SHUT_RDWR);
      echo '請使用遠程dns解析.', PHP_EOL;
    }

    stream_socket_sendto($this->fd, "\x05\x00\x00\x01\x00\x00\x00\x00\x00\x00");
    echo "{$domain}:{$port}", PHP_EOL;
    $remote = stream_socket_client("tcp://{$domain}:{$port}");
    if ($remote === false) {
      stream_socket_shutdown($this->fd, STREAM_SHUT_RDWR);
      return;
    }

    $pool = $this->worker->pipePool;

    $pipe1 = new Pipe($remote, $this->fd);
    $pipe2 = new Pipe($this->fd, $remote);

    $pool->submit($pipe1);
    $pool->submit($pipe2);
  }
}

class ProxyWorker extends Worker
{
  public $pipePool;
  public function __construct($pipePool)
  {
    $this->pipePool = $pipePool;
  }
}

$server = stream_socket_server('tcp://0.0.0.0:1080', $errno, $errstr);
if ($server === false)
  exit($errstr);

$pipePool = new Pool(200, Worker::class);
$pool = new Pool(50, 'ProxyWorker', [$pipePool]);

for( ; ; ) {
  $fd = @stream_socket_accept($server, 60);
  if ($fd === false)
    continue;
  $pool->submit(new Client($fd));
}

相關(guān)文章

  • php輕松實現(xiàn)文件上傳功能

    php輕松實現(xiàn)文件上傳功能

    這篇文章主要介紹了php輕松實現(xiàn)文件上傳功能的全部代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-03-03
  • 部署PHP時的4個配置修改說明

    部署PHP時的4個配置修改說明

    這篇文章主要介紹了部署PHP時的4個配置修改說明,非常重要的四點配置修改,希望大家認(rèn)真閱讀本文。
    2015-10-10
  • php生成并下載word文件到本地實現(xiàn)方法詳解

    php生成并下載word文件到本地實現(xiàn)方法詳解

    要給最常用出租屋管理系統(tǒng)增加個合同功能,mark下知識點。要生成合同就需要使用phpword。文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • php下Memcached入門實例解析

    php下Memcached入門實例解析

    這篇文章主要介紹了php下Memcached入門實例,較為詳細的分析了memcached的概念與用法,是非常實用的技巧,需要的朋友可以參考下
    2015-01-01
  • php常用字符串查找函數(shù)strstr()與strpos()實例分析

    php常用字符串查找函數(shù)strstr()與strpos()實例分析

    這篇文章主要介紹了php常用字符串查找函數(shù)strstr()與strpos(),結(jié)合具體實例形式分析了php字符串查找函數(shù)strstr()與strpos()的具體功能、用法、區(qū)別及相關(guān)操作注意事項,需要的朋友可以參考下
    2019-06-06
  • PHP連接sql server 2005環(huán)境配置及問題解決

    PHP連接sql server 2005環(huán)境配置及問題解決

    這篇文章主要介紹了PHP連接sql server 2005環(huán)境配置及問題解決,需要的朋友可以參考下
    2014-08-08
  • 一款簡單實用的php操作mysql數(shù)據(jù)庫類

    一款簡單實用的php操作mysql數(shù)據(jù)庫類

    這篇文章主要介紹了一款簡單實用的php操作mysql數(shù)據(jù)庫類,不但包含了php針對mysql數(shù)據(jù)庫的常見操作之外,還有針對危險字符的過濾功能,非常具有實用價值,需要的朋友可以參考下
    2014-12-12
  • C#靜態(tài)方法與非靜態(tài)方法實例分析

    C#靜態(tài)方法與非靜態(tài)方法實例分析

    這篇文章主要介紹了C#靜態(tài)方法與非靜態(tài)方法,重點講述了靜態(tài)方法的實際應(yīng)用,有助于進一步加深對C#程序設(shè)計的理解,需要的朋友可以參考下
    2014-09-09
  • php array_map()函數(shù)實例用法

    php array_map()函數(shù)實例用法

    在本篇文章里小編給大家分享了一篇關(guān)于php array_map()函數(shù)實例用法,有興趣的朋友們可以學(xué)習(xí)下。
    2021-03-03
  • 淺談PHP中JSON數(shù)據(jù)操作

    淺談PHP中JSON數(shù)據(jù)操作

    本文的知識點:1、JSON數(shù)據(jù)格式介紹,2、對數(shù)據(jù)編碼成JSON格式,3、對JSON數(shù)據(jù)進行解碼,并操作,有需要的小伙伴可以參考下。
    2015-07-07

最新評論

专栏| 津南区| 施秉县| 阿拉善右旗| 昭通市| 玛多县| 马鞍山市| 东乌| 永春县| 东城区| 封丘县| 桂东县| 邯郸县| 乌鲁木齐县| 新干县| 金川县| 丹江口市| 南靖县| 巴林左旗| 麦盖提县| 体育| 商城县| 来宾市| 报价| 攀枝花市| 赤峰市| 盘锦市| 定远县| 临颍县| 大邑县| 钟祥市| 朝阳县| 兴宁市| 甘肃省| 柳河县| 扶余县| 项城市| 曲松县| 民权县| 杭锦后旗| 华安县|