怎么用PHP实现简单的Socks5 Server
发表于:2025-12-02 作者:千家信息网编辑
千家信息网最后更新 2025年12月02日,本篇内容主要讲解"怎么用PHP实现简单的Socks5 Server",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"怎么用PHP实现简单的Socks5 Ser
千家信息网最后更新 2025年12月02日怎么用PHP实现简单的Socks5 Server
本篇内容主要讲解"怎么用PHP实现简单的Socks5 Server",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"怎么用PHP实现简单的Socks5 Server"吧!
利用 Phalcon7 的异步功能实现,完整源码 https://github.com/dreamsxin/cphalcon7/blob/master/examples/async/Socks5Server.php。
concurrency = max(1, $concurrency); $this->channel = new \Phalcon\Async\Channel($capacity); $this->context = \Phalcon\Async\Context::background(); } public function close(?\Throwable $e = null): void { $this->count = \PHP_INT_MAX; $this->channel->close($e); } public function submit(callable $work, $socket, ...$args): \Phalcon\Async\Awaitable { if ($this->count < $this->concurrency) { $this->count++; Socks5Server::info('Pool count '.$this->count); \Phalcon\Async\Task::asyncWithContext($this->context, static function (iterable $it) { try { foreach ($it as list ($defer, $context, $work, $socket, $args)) { try { $defer->resolve($context->run($work, $socket, ...$args)); } catch (\Throwable $e) { Socks5Server::err($e->getMessage()); $defer->fail($e); } finally { } } } catch (\Throwable $e) { Socks5Server::err($e->getMessage()); } finally { --$this->count; } }, $this->channel->getIterator()); } $this->channel->send([ $defer = new \Phalcon\Async\Deferred(), \Phalcon\Async\Context::current(), $work, $socket, $args ]); return $defer->awaitable(); }}class Socks5Server{ static public $debug = false; private $server; private $host; private $port; private $clients; public function __construct($host, $port, callable $callback = NULL, int $concurrency = 1, int $capacity = 0) { $this->host = $host; $this->port = $port; $this->callback = $callback; $this->pool = new Pool($concurrency, $capacity); } public function start() { $callback = $this->callback; $ws = $this; $worker = static function ($socket) use ($ws, $callback) { $socket->status = Socks5::STATUS_INIT; $socket->is_closing = false; try { $buffer = ''; while (!$socket->is_closing && null !== ($chunk = $socket->read())) { $buffer .= $chunk; switch ($socket->status) { case Socks5::STATUS_INIT: /** * 协商版本以及验证方式 * +---------+-----------------+------------------+ * |协议版本 |支持的验证式数量 |验证方式 | * +---------+-----------------+------------------+ * |1个字节 |1个字节 |1种式占一个字节 | * +---------+-----------------+------------------+ * |0x05 |0x02 |0x00,0x02 | * +---------+-----------------+------------------+ */ /** * 0x00 无验证需求 * 0x01 通用安全服务应用程序接口(GSSAPI) * 0x02 用户名/密码(USERNAME/PASSWORD) * 0x03 至 X'7F' IANA 分配(IANA ASSIGNED) * 0x80 至 X'FE' 私人方法保留(RESERVED FOR PRIVATE METHODS) * 0xFF 无可接受方法(NO ACCEPTABLE METHODS) */ $authtypes = Socks5::parseAuth($buffer); if ($authtypes === false) { $socket->is_closing = true; break; } if ($authtypes === true) { // continue break; } $socket->status = Socks5::STATUS_ADDR; $socket->write("\x05\x00"); // TODO: 暂时 $buffer = ''; break; case Socks5::STATUS_AUTH: if ($callback && \is_callable($callback)) { // TODO } break; case Socks5::STATUS_ADDR: self::info('Socks5::STATUS_ADDR'); /** * 建立代理连接 * +----------+------------+---------+-----------+-----------------------+------------+ * |协议版本 |请求的类型 |保留字段 |地址类型 |地址数据 |地址端口 | * +----------+------------+---------+-----------+-----------------------+------------+ * |1个字节 |1个字节 |1个字节 |1个字节 |变长 |2个字节 | * +----------+------------+---------+-----------+-----------------------+------------+ * |0x05 |0x01 |0x00 |0x01 |0x0a,0x00,0x01,0x0a |0x00,0x50 | * +----------+------------+---------+-----------+-----------------------+------------+ */ /** * 请求类型 * CONNECT : 0x01, 建立代理连接 * BIND : 0x02,告诉代理服务器监听目标机器的连接,也就是让代理服务器创建socket监听来自目标机器的连接。FTP这类需要服务端主动联接客户端的的应用场景。 * 1. 只有在完成了connnect操作之后才能进行bind操作 * 2. bind操作之后,代理服务器会有两次响应, 第一次响应是在创建socket监听完成之后,第二次是在目标机器连接到代理服务器上之后。 * UDP ASSOCIATE : 0x03, udp 协议请求代理。 */ if (strlen($buffer) < 2) { break; } $cmd = ord($buffer[1]); if ($cmd != Socks5::CMD_CONNECT) { self::err("Bad command ".$cmd); $socket->is_closing = true; break; } $headers = Socks5::parseAddr($buffer); if (!$headers) { self::err('Error header'); $socket->is_closing = true; break; } if ($headers === true) { // continue break; } /** * 数据包转发 * +----+------+------+----------+----------+----------+ * |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA | * +----+------+------+----------+----------+----------+ * | 2 | 1 | 1 | Variable | 2 | Variable | * +----+------+------+----------+----------+----------+ */ $buffer = substr($buffer, $headers[3]); $socket->status = Socks5::STATUS_CONNECTING; if (!in_array($headers[0], [Socks5::TYPE_IPV4, Socks5::TYPE_HOST, Socks5::TYPE_IPV6])) { self::err('Addr type error'); $socket->is_closing = true; break; } $tls = NULL; if ($headers[2] == 443) { $tls = new \Phalcon\Async\Network\TlsClientEncryption(); $tls = $tls->withAllowSelfSigned(true); } $socket->client = \Phalcon\Async\Network\TcpSocket::connect($headers[1], $headers[2], $tls); $socket->write(Socks5::REPLY_ADDR); $socket->status = Socks5::STATUS_STREAM; \Phalcon\Async\Task::async(function ($client) use ($socket) { while (!$socket->is_closing && null !== ($chunk = $client->read())) { $socket->write($chunk); } }, $socket->client); break; case Socks5::STATUS_STREAM: self::info('Socks5::STATUS_STREAM'); $socket->client->write($buffer); $buffer = ''; break; } } } catch (\Throwable $e) { self::err($e->getMessage()); } finally { $socket->close(); } }; try { $this->server = \Phalcon\Async\Network\TcpServer::listen($this->host, $this->port); echo Phalcon\Cli\Color::info('start server listen:'.$this->host.':'.$this->port).PHP_EOL; while (true) { $socket = $this->server->accept(); if ($socket === false) { continue; } $this->pool->submit($worker, $socket); } } catch (\Throwable $e) { self::err($e->getMessage()); } finally { if ($this->server) { $this->server->close(); } } } static public function info($message) { if (self::$debug) { echo Phalcon\Cli\Color::info($message).PHP_EOL; } } static public function err($message) { echo Phalcon\Cli\Color::error($message).PHP_EOL; }}$opts = new \Phalcon\Cli\Options('Websocket CLI');$opts->add([ 'type' => \Phalcon\Cli\Options::TYPE_STRING, 'name' => 'server', 'shortName' => 's', 'required' => false, // 可选,需要用=号赋值 'help' => "address"]);$opts->add([ 'type' => \Phalcon\Cli\Options::TYPE_INT, 'name' => 'port', 'shortName' => 'p', 'required' => false, 'help' => "port"]);$opts->add([ 'type' => \Phalcon\Cli\Options::TYPE_BOOLEAN, 'name' => 'concurrency', 'shortName' => 'c', 'required' => false]);$opts->add([ 'type' => \Phalcon\Cli\Options::TYPE_BOOLEAN, 'name' => 'capacity', 'shortName' => 'C', 'required' => false]);$opts->add([ 'type' => \Phalcon\Cli\Options::TYPE_BOOLEAN, 'name' => 'debug', 'shortName' => 'v', 'required' => false, 'help' => "enable debug"]);$vals = $opts->parse();if ($vals === false ) { exit;}/** * 运行 php websocket-server.php */if (isset($vals['debug'])) { Socks5Server::$debug = true; echo Phalcon\Cli\Color::info('Use debug mode').PHP_EOL;}$sserver = new Socks5Server(\Phalcon\Arr::get($vals, 'server', '0.0.0.0'), \Phalcon\Arr::get($vals, 'port', 10002), function($socket, $status, $data) { // TODO}, \Phalcon\Arr::get($vals, 'concurrency', 500), \Phalcon\Arr::get($vals, 'capacity', 1));$sserver->start();到此,相信大家对"怎么用PHP实现简单的Socks5 Server"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
字节
代理
服务
服务器
验证
地址
方法
机器
版本
目标
类型
监听
内容
数据
方式
是在
学习
应用
实用
更深
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
游戏软件开发赚钱嘛
网络安全教育主题班会微课
数据库应用基础6到8章
小企业服务器硬盘
青海软件开发模型
优网服务器
网络技术启蒙
石狮辛巴网络技术公司怎么样
软件开发系统设计步骤
网络安全对民用安全的影响
新建数据库用户时
网络技术最新技术新闻
服务器信息传输协议是什么意思
微信组件如何绑定数据库
游戏设计软件开发专业
软件开发技术保障
软件开发主要业绩描述
网络技术进行大型会展策划
网络安全实验木马演示实验
数据库登录界面
网络技术如何帮助企业制定战略
计算器网络技术拓补
数字网络技术对广告行业的影响
苏州综合服务管理软件开发
2012年魔兽世界服务器排名
网吧如何落实 网络安全法
云服务器管理终端持续黑屏
网络技术进行大型会展策划
城管局网络安全宣传周
2021网络安全周是第几届