react / dns
ReactPHP 的异步 DNS 解析器
Requires
- php: >=5.3.0
- react/cache: ^1.0 || ^0.6 || ^0.5
- react/event-loop: ^1.2
- react/promise: ^3.2 || ^2.7 || ^1.2.1
Requires (Dev)
- phpunit/phpunit: ^9.6 || ^5.7 || ^4.8.36
- react/async: ^4.3 || ^3 || ^2
- react/promise-timer: ^1.11
- 3.x-dev
- 1.x-dev
- v1.13.0
- v1.12.0
- v1.11.0
- v1.10.0
- v1.9.0
- v1.8.0
- v1.7.0
- v1.6.0
- v1.5.0
- v1.4.0
- v1.3.0
- v1.2.0
- v1.1.0
- v1.0.0
- v0.4.19
- v0.4.18
- v0.4.17
- v0.4.16
- v0.4.15
- v0.4.14
- v0.4.13
- v0.4.12
- v0.4.11
- v0.4.10
- v0.4.9
- v0.4.8
- v0.4.7
- v0.4.6
- v0.4.5
- v0.4.4
- v0.4.3
- v0.4.2
- v0.4.1
- v0.4.0
- v0.3.2
- v0.3.0
- v0.2.6
- v0.2.5
- v0.2.4
- v0.2.3
- v0.2.2
- v0.2.1
- v0.2.0
This package is auto-updated.
Last update: 2024-09-13 14:47:20 UTC
README
ReactPHP 的异步 DNS 解析器。
开发版本:此分支包含即将推出的 v3 版本的代码。要查看当前稳定版 v1 的代码,请查看
1.x
分支。即将推出的 v3 版本将是此包的发展方向。然而,我们仍将积极支持 v1,以帮助那些尚未升级到最新版本的用户。有关更多详细信息,请参阅 安装说明。
DNS 组件的主要目的是提供异步 DNS 解析。然而,它实际上是一个用于处理 DNS 消息的工具包,可以很容易地用于创建 DNS 服务器。
目录
基本用法
最基本的用法是只需通过解析器工厂创建一个解析器。您只需要提供一台域名服务器,然后您就可以开始解析名称了!
$config = React\Dns\Config\Config::loadSystemConfigBlocking(); if (!$config->nameservers) { $config->nameservers[] = '8.8.8.8'; } $factory = new React\Dns\Resolver\Factory(); $dns = $factory->create($config); $dns->resolve('igor.io')->then(function ($ip) { echo "Host: $ip\n"; });
请参阅 第一个示例。
可以使用 Config
类来加载系统默认配置。这可能是一种会访问文件系统并阻塞的操作。因此,理想情况下,此方法应在循环开始之前仅执行一次,而不是在运行时重复执行。请注意,如果无法加载系统配置,则此类可能返回一个 空的 配置。因此,如果您找不到任何配置,您可能希望像上面那样应用默认域名服务器。
请注意,工厂在创建解析器实例时,一次从文件系统中加载 hosts 文件。因此,理想情况下,此方法应在循环开始之前仅执行一次,而不是在运行时重复执行。
但这不仅仅如此。
缓存
您可以通过配置解析器以使用 CachedExecutor
来缓存结果
$config = React\Dns\Config\Config::loadSystemConfigBlocking(); if (!$config->nameservers) { $config->nameservers[] = '8.8.8.8'; } $factory = new React\Dns\Resolver\Factory(); $dns = $factory->createCached($config); $dns->resolve('igor.io')->then(function ($ip) { echo "Host: $ip\n"; }); ... $dns->resolve('igor.io')->then(function ($ip) { echo "Host: $ip\n"; });
如果第一个调用在第二个之前返回,则只执行一个查询。第二个结果将从内存缓存中提供。这对于需要多次查找相同主机名的长时间运行脚本非常有用。
请参阅 第三个示例。
自定义缓存适配器
默认情况下,以上将使用内存缓存。
您还可以指定一个自定义缓存,实现 CacheInterface
以处理记录缓存
$cache = new React\Cache\ArrayCache(); $factory = new React\Dns\Resolver\Factory(); $dns = $factory->createCached('8.8.8.8', null, $cache);
请参阅维基百科了解可能的 缓存实现。
ResolverInterface
resolve()
可以使用 resolve(string $domain): PromiseInterface<string>
方法将给定的 $domain 名称解析为单个 IPv4 地址(类型 A
查询)。
$resolver->resolve('reactphp.org')->then(function ($ip) { echo 'IP for reactphp.org is ' . $ip . PHP_EOL; });
这是此包中的主要方法之一。它向您的 DNS 服务器发送一个针对给定 $domain 名称的 DNS 查询,并在成功时返回一个 IP 地址。
如果DNS服务器发送的DNS响应消息包含针对此查询的多个IP地址,它将随机从响应中选取一个IP地址。如果您想获取完整的IP地址列表或想要发送不同类型的查询,请使用resolveAll()
方法。
如果DNS服务器发送的DNS响应消息指示错误代码,此方法将拒绝并返回RecordNotFoundException
。可以使用其消息和代码来检查响应代码。
如果DNS通信失败,服务器没有响应有效的响应消息,此消息将拒绝并返回Exception
。
可以通过取消其挂起的Promise来取消挂起的DNS查询。
$promise = $resolver->resolve('reactphp.org'); $promise->cancel();
resolveAll()
resolveAll(string $host, int $type): PromiseInterface<array>
方法可以用来解析给定域名和查询类型的所有记录值。
$resolver->resolveAll('reactphp.org', Message::TYPE_A)->then(function ($ips) { echo 'IPv4 addresses for reactphp.org ' . implode(', ', $ips) . PHP_EOL; }); $resolver->resolveAll('reactphp.org', Message::TYPE_AAAA)->then(function ($ips) { echo 'IPv6 addresses for reactphp.org ' . implode(', ', $ips) . PHP_EOL; });
这是本包中的主要方法之一。它将针对给定的域名向您的DNS服务器发送DNS查询,并在成功时返回所有记录值列表。
如果DNS服务器发送的DNS响应消息包含针对此查询的一个或多个记录,它将返回一个包含所有记录值的列表。您可以使用Message::TYPE_*
常量来控制发送哪种类型的查询。请注意,此方法始终返回记录值列表,但每种记录值类型取决于查询类型。例如,它返回类型为A
的查询的IPv4地址,类型为AAAA
的查询的IPv6地址,类型为NS
、CNAME
和PTR
的查询的域名,以及其他查询的结构化数据。有关更多详细信息,请参阅Record
文档。
如果DNS服务器发送的DNS响应消息指示错误代码,此方法将拒绝并返回RecordNotFoundException
。可以使用其消息和代码来检查响应代码。
如果DNS通信失败,服务器没有响应有效的响应消息,此消息将拒绝并返回Exception
。
可以通过取消其挂起的Promise来取消挂起的DNS查询。
$promise = $resolver->resolveAll('reactphp.org', Message::TYPE_AAAA); $promise->cancel();
高级用法
UdpTransportExecutor
可以使用UdpTransportExecutor
通过UDP传输发送DNS查询。
这是发送DNS查询到您的DNS服务器的主体类,并由Resolver
内部用于实际消息传输。
对于更高级的用法,可以直接使用此类。以下示例查找igor.io
的IPv6地址。
$executor = new UdpTransportExecutor('8.8.8.8:53'); $executor->query( new Query($name, Message::TYPE_AAAA, Message::CLASS_IN) )->then(function (Message $message) { foreach ($message->answers as $answer) { echo 'IPv6: ' . $answer->data . PHP_EOL; } }, 'printf');
另请参阅第四个示例。
请注意,此执行器不实现超时,因此您可能希望将其与TimeoutExecutor
一起使用,如下所示
$executor = new TimeoutExecutor( new UdpTransportExecutor($nameserver), 3.0 );
此外,请注意,此执行器使用不可靠的UDP传输,并且没有实现任何重试逻辑,因此您可能希望将其与RetryExecutor
一起使用,如下所示
$executor = new RetryExecutor( new TimeoutExecutor( new UdpTransportExecutor($nameserver), 3.0 ) );
请注意,此执行器完全异步,因此您可以使用它并发地执行任意数量的查询。您可能需要在您的应用程序中限制并发查询的数量,否则您可能会遇到速率限制和解析器端禁用。对于许多常见应用,您可能希望避免在第一个查询仍在挂起时发送相同的查询,因此您可能希望将其与CoopExecutor
一起使用,如下所示
$executor = new CoopExecutor( new RetryExecutor( new TimeoutExecutor( new UdpTransportExecutor($nameserver), 3.0 ) ) );
内部,此类使用PHP的UDP套接字,并且出于组织原因,没有利用react/datagram,以避免两个包之间的循环依赖。高级组件应利用数据报组件,而不是从头开始重新实现此套接字逻辑。
TcpTransportExecutor
可以使用TcpTransportExecutor
类通过TCP/IP流传输发送DNS查询。
这是发送DNS查询到您的DNS服务器的主体类之一。
对于更高级的使用,可以直接使用此类。以下示例查找reactphp.org
的IPv6
地址。
$executor = new TcpTransportExecutor('8.8.8.8:53'); $executor->query( new Query($name, Message::TYPE_AAAA, Message::CLASS_IN) )->then(function (Message $message) { foreach ($message->answers as $answer) { echo 'IPv6: ' . $answer->data . PHP_EOL; } }, 'printf');
另请参阅示例#92。
请注意,此执行器不实现超时,因此您可能希望将其与TimeoutExecutor
一起使用,如下所示
$executor = new TimeoutExecutor( new TcpTransportExecutor($nameserver), 3.0 );
与UdpTransportExecutor
不同,此类使用可靠的TCP/IP传输,因此您不一定必须实现任何重试逻辑。
请注意,此执行器完全是异步的,因此允许您并发执行查询。第一个查询将建立到DNS服务器的TCP/IP套接字连接,该连接将保持短暂开放。额外的查询将自动重用到DNS服务器的现有套接字连接,通过此单个连接管道多个请求,并保持空闲连接短暂开放。如果只发送偶尔的查询,初始TCP/IP连接开销可能会产生轻微的延迟 - 当通过现有连接发送更多并发查询时,它变得越来越高效,避免了创建像基于UDP的执行器那样的大量并发套接字。您可能仍然想要限制应用程序中(并发)查询的数量,或者您可能面临解析器端的速率限制和封禁。对于许多常见应用程序,您可能希望在第一个查询仍在挂起时避免发送相同的查询多次,因此您可能希望将其与CoopExecutor
等结合使用
$executor = new CoopExecutor( new TimeoutExecutor( new TcpTransportExecutor($nameserver), 3.0 ) );
内部,此类使用PHP的TCP/IP套接字,并非出于对react/socket的利用,纯粹是为了组织原因,以避免两个包之间的循环依赖。高级组件应利用套接字组件而不是从头开始重新实现此套接字逻辑。
SelectiveTransportExecutor
SelectiveTransportExecutor
类可用于通过UDP或TCP/IP流传输发送DNS查询。
此类将自动选择正确的传输协议向您的DNS服务器发送DNS查询。它始终尝试首先通过更高效的UDP传输发送。如果此查询产生与大小相关的问题(截断的消息),它将尝试通过流式TCP/IP传输重试。
对于更高级的使用,可以直接使用此类。以下示例查找reactphp.org
的IPv6
地址。
$executor = new SelectiveTransportExecutor($udpExecutor, $tcpExecutor); $executor->query( new Query($name, Message::TYPE_AAAA, Message::CLASS_IN) )->then(function (Message $message) { foreach ($message->answers as $answer) { echo 'IPv6: ' . $answer->data . PHP_EOL; } }, 'printf');
请注意,此执行器仅实现了选择给定DNS查询的正确传输逻辑。实现正确的传输逻辑、实现超时和任何重试逻辑留给给定的执行器,有关更多详细信息,请参阅UdpTransportExecutor
和TcpTransportExecutor
。
请注意,此执行器完全异步,因此您可以使用它并发地执行任意数量的查询。您可能需要在您的应用程序中限制并发查询的数量,否则您可能会遇到速率限制和解析器端禁用。对于许多常见应用,您可能希望避免在第一个查询仍在挂起时发送相同的查询,因此您可能希望将其与CoopExecutor
一起使用,如下所示
$executor = new CoopExecutor( new SelectiveTransportExecutor( $datagramExecutor, $streamExecutor ) );
HostsFileExecutor
请注意,上述UdpTransportExecutor
类始终执行实际的DNS查询。如果您还希望考虑主机文件中的条目,可以使用以下代码
$hosts = \React\Dns\Config\HostsFile::loadFromPathBlocking(); $executor = new UdpTransportExecutor('8.8.8.8:53'); $executor = new HostsFileExecutor($hosts, $executor); $executor->query( new Query('localhost', Message::TYPE_A, Message::CLASS_IN) );
安装
安装此库的推荐方法是通过Composer。 初识Composer?
一旦发布,此项目将遵循SemVer。目前,这将安装最新开发版本
composer require react/dns:^3@dev
有关版本升级的详细信息,请参阅CHANGELOG。
该项目旨在在任何平台上运行,因此不要求任何PHP扩展,并支持在PHP 7.1到当前PHP 8+上运行。强烈建议为此项目使用最新支持的PHP版本。
测试
要运行测试套件,您首先需要克隆此仓库,然后通过Composer安装所有依赖项
composer install
要运行测试套件,请转到项目根目录并运行
vendor/bin/phpunit
测试套件还包含一些依赖于稳定互联网连接的功能集成测试。如果您不想运行这些测试,可以像这样简单地跳过
vendor/bin/phpunit --exclude-group internet
许可
麻省理工学院,请参阅许可证文件。