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


Posted in PHP onMay 05, 2016
100多行PHP代码实现socks5代理服务器,这次是使用swoole纯异步来写,使用状态机来处理数据。目前用它访问开源中国木有压力,但访问网易新闻就压力山大。我发现我用别的语言写得代理,访问网易新闻都压力大。嘎嘎,学艺不精。
对swoole理解不深,不知道怎么处理socket shutdown只关闭读/写这样,还有就是连接超时,读写超时这种怎么处理。在网上看到作者说要用定时器,感觉好麻烦,所以,这次的代理,虽然个人用,一般不会有什么问题,但离产品级的代理,还有段路要走。

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



<?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 '协议不正确:' . $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为空时的处理。貌似不存在的域名都解析成了本机的外网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 相关文章推荐
PHP5中MVC结构学习
Oct 09 PHP
提问的智慧
Oct 09 PHP
PHP 时间转换Unix时间戳代码
Jan 22 PHP
一篇有意思的技术文章php介绍篇
Oct 26 PHP
PHP序列号生成函数和字符串替换函数代码
Jun 07 PHP
php随机输出名人名言的代码
Oct 07 PHP
php全局变量和类配合使用深刻理解
Jun 05 PHP
php中$美元符号与Zen Coding冲突问题解决方法分享
May 28 PHP
MacOS 安装 PHP的图片裁剪扩展Tclip
Mar 25 PHP
dvwa+xampp搭建显示乱码的问题及解决方案
Aug 23 PHP
php实现的读取CSV文件函数示例
Feb 07 PHP
PHP面向对象之里氏替换原则简单示例
Apr 08 PHP
PHP随机数 C扩展随机数
May 04 #PHP
PHP正则表达式过滤html标签属性(DEMO)
May 04 #PHP
Joomla使用Apache重写模式的方法
May 04 #PHP
Joomla开启SEF的方法
May 04 #PHP
Joomla简单判断用户是否登录的方法
May 04 #PHP
Joomla实现组件中弹出一个模式(modal)窗口的方法
May 04 #PHP
joomla组件开发入门教程
May 04 #PHP
You might like
js 方法实现返回多个数据的代码
2009/04/30 Javascript
javascript下判断一个元素是否存在的代码
2010/03/05 Javascript
Jquery 滑入滑出效果实现代码
2010/03/27 Javascript
对象无length属性时IE6/IE7中无法将其转换成伪数组(ArrayLike)
2011/07/31 Javascript
javascript显式类型转换实例分析
2015/04/25 Javascript
Jquery on方法绑定事件后执行多次的解决方法
2016/06/02 Javascript
JavaScript实战之菜单特效
2016/08/16 Javascript
jquery对Json的各种遍历方法总结(必看篇)
2016/09/29 Javascript
详解angular2封装material2对话框组件
2017/03/03 Javascript
Node.js实现连接mysql数据库功能示例
2017/09/15 Javascript
Angular父组件调用子组件的方法
2018/04/02 Javascript
JS中数据结构之栈
2019/01/01 Javascript
详解JavaScript对数组操作(添加/删除/截取/排序/倒序)
2019/04/28 Javascript
使用Vue Composition API写出清晰、可扩展的表单实现
2020/06/10 Javascript
js实现三角形粒子运动
2020/09/22 Javascript
[03:14]2014DOTA2西雅图国际邀请赛 EG战队巡礼
2014/07/07 DOTA
sqlalchemy对象转dict的示例
2014/04/22 Python
python生成日历实例解析
2014/08/21 Python
python中的reduce内建函数使用方法指南
2014/08/31 Python
Python数字图像处理之霍夫线变换实现详解
2018/01/12 Python
django中的HTML控件及参数传递方法
2018/03/20 Python
Numpy array数据的增、删、改、查实例
2018/06/04 Python
基于Python获取城市近7天天气预报
2019/11/26 Python
TENSORFLOW变量作用域(VARIABLE SCOPE)
2020/01/10 Python
windows支持哪个版本的python
2020/07/03 Python
工程力学硕士生的自我评价范文
2013/11/16 职场文书
食品厂厂长岗位职责
2014/01/30 职场文书
洗发水广告词
2014/03/13 职场文书
动画设计系毕业生求职信
2014/07/15 职场文书
建筑专业毕业生求职信
2014/09/30 职场文书
学雷锋活动简报
2015/07/20 职场文书
2016年学习雷锋精神广播稿
2015/12/17 职场文书
如何用RabbitMQ和Swoole实现一个异步任务系统
2021/05/29 PHP
Jackson 反序列化时实现大小写不敏感设置
2021/06/29 Java/Android
Python爬虫网络请求之代理服务器和动态Cookies
2022/04/12 Python
Android开发手册TextInputLayout样式使用示例
2022/06/10 Java/Android