TcpTransportExecutor
in package
implements
ExecutorInterface
Send DNS queries over a TCP/IP stream transport.
This is one of the main classes that send a DNS query to your DNS server.
For more advanced usages one can utilize this class directly.
The following example looks up the IPv6
address for reactphp.org
.
$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');
See also example #92.
Note that this executor does not implement a timeout, so you will very likely
want to use this in combination with a TimeoutExecutor
like this:
$executor = new TimeoutExecutor(
new TcpTransportExecutor($nameserver),
3.0
);
Unlike the UdpTransportExecutor
, this class uses a reliable TCP/IP
transport, so you do not necessarily have to implement any retry logic.
Note that this executor is entirely async and as such allows you to execute
queries concurrently. The first query will establish a TCP/IP socket
connection to the DNS server which will be kept open for a short period.
Additional queries will automatically reuse this existing socket connection
to the DNS server, will pipeline multiple requests over this single
connection and will keep an idle connection open for a short period. The
initial TCP/IP connection overhead may incur a slight delay if you only send
occasional queries – when sending a larger number of concurrent queries over
an existing connection, it becomes increasingly more efficient and avoids
creating many concurrent sockets like the UDP-based executor. You may still
want to limit the number of (concurrent) queries in your application or you
may be facing rate limitations and bans on the resolver end. For many common
applications, you may want to avoid sending the same query multiple times
when the first one is still pending, so you will likely want to use this in
combination with a CoopExecutor
like this:
$executor = new CoopExecutor(
new TimeoutExecutor(
new TcpTransportExecutor($nameserver),
3.0
)
);
Internally, this class uses PHP's TCP/IP sockets and does not take advantage of react/socket purely for organizational reasons to avoid a cyclic dependency between the two packages. Higher-level components should take advantage of the Socket component instead of reimplementing this socket logic from scratch.
Table of Contents
Interfaces
Properties
- $dumper : mixed
- $idlePeriod : float
- Maximum idle time when socket is current unused (i.e. no pending queries outstanding)
- $idleTimer : TimerInterface|null
- $loop : mixed
- $names : array<string|int, string>
- $nameserver : mixed
- $parser : mixed
- $pending : array<string|int, Deferred>
- $readBuffer : mixed
- $readChunk : string
- $readPending : mixed
- $socket : resource|null
- $writeBuffer : mixed
- $writePending : mixed
Methods
- __construct() : mixed
- query() : PromiseInterface<string|int, Message>
- Executes a query and will return a response message
Properties
$dumper
private
mixed
$dumper
$idlePeriod
Maximum idle time when socket is current unused (i.e. no pending queries outstanding)
private
float
$idlePeriod
= 0.001
If a new query is to be sent during the idle period, we can reuse the existing socket without having to wait for a new socket connection. This uses a rather small, hard-coded value to not keep any unneeded sockets open and to not keep the loop busy longer than needed.
A future implementation may take advantage of edns-tcp-keepalive
to keep
the socket open for longer periods. This will likely require explicit
configuration because this may consume additional resources and also keep
the loop busy for longer than expected in some applications.
Tags
$idleTimer
private
TimerInterface|null
$idleTimer
$loop
private
mixed
$loop
$names
private
array<string|int, string>
$names
= array()
$nameserver
private
mixed
$nameserver
$parser
private
mixed
$parser
$pending
private
array<string|int, Deferred>
$pending
= array()
$readBuffer
private
mixed
$readBuffer
= ''
$readChunk
private
string
$readChunk
= 0xffff
$readPending
private
mixed
$readPending
= false
$socket
private
resource|null
$socket
$writeBuffer
private
mixed
$writeBuffer
= ''
$writePending
private
mixed
$writePending
= false
Methods
__construct()
public
__construct(string $nameserver[, LoopInterface|null $loop = null ]) : mixed
Parameters
- $nameserver : string
- $loop : LoopInterface|null = null
query()
Executes a query and will return a response message
public
query(Query $query) : PromiseInterface<string|int, Message>
It returns a Promise which either fulfills with a response
React\Dns\Model\Message
on success or rejects with an Exception
if
the query is not successful. A response message may indicate an error
condition in its rcode
, but this is considered a valid response message.
$executor->query($query)->then(
function (React\Dns\Model\Message $response) {
// response message successfully received
var_dump($response->rcode, $response->answers);
},
function (Exception $error) {
// failed to query due to $error
}
);
The returned Promise MUST be implemented in such a way that it can be cancelled when it is still pending. Cancelling a pending promise MUST reject its value with an Exception. It SHOULD clean up any underlying resources and references as applicable.
$promise = $executor->query($query);
$promise->cancel();
Parameters
- $query : Query
Return values
PromiseInterface<string|int, Message> —resolves with response message on success or rejects with an Exception on error