3.Netty TCP客户端(TcpClient)

目录


Netty专栏目录(点击进入…)


Netty TCP客户端(TcpClient)

Reactor Netty提供了易于使用和易于配置的TcpClient。它隐藏了创建TCP客户端所需的大部分 Netty功能,并添加了Reactive Streams背压(Reactive Streams是具有无阻塞背压的异步流处理的标准)

连接和断开

要将TCP客户端连接到给定端点,必须创建并配置一个 TcpClient实例。默认情况下,host是localhost和port是12012

创建一个TcpClient:
返回的Connection提供了一个简单的连接 API,包括disposeNow(),它以阻塞方式关闭客户端

import reactor.netty.Connection;
import reactor.netty.tcp.TcpClient;

public class Application {

	public static void main(String[] args) {
		Connection connection =
				TcpClient.create() // 创建一个TcpClient 准备好配置的实例
				         .connectNow(); // 以阻塞方式连接客户端并等待它完成初始化

		connection.onDispose()
		          .block();
	}
	
}

主机和端口

要连接到特定的host和port,可以将以下配置应用到TCP客户端

import reactor.netty.Connection;
import reactor.netty.tcp.TcpClient;

public class Application {

	public static void main(String[] args) {
		Connection connection =
				TcpClient.create()
				         .host("example.com")  // 配置TCP主机
				         .port(80)        // 配置TCP端口    
				         .connectNow();

		connection.onDispose()
		          .block();
	}
	
}

急切初始化

默认情况下,TcpClient资源的初始化是按需进行的。这意味着connect operation吸收了初始化和加载所需的额外时间

当需要预加载这些资源时,可以进行TcpClient如下配置:

import reactor.core.publisher.Mono;
import reactor.netty.Connection;
import reactor.netty.tcp.TcpClient;

public class Application {

	public static void main(String[] args) {
		TcpClient tcpClient =
				TcpClient.create()
				         .host("example.com")
				         .port(80)
				         .handle((inbound, outbound) -> outbound.sendString(Mono.just("hello")));
         // 初始化并加载事件循环组、主机名解析器、本机传输库和用于安全性的本机库
		tcpClient.warmup() 
		         .block();
         // 连接到远程对等方时发生主机名解析
		Connection connection = tcpClient.connectNow(); 

		connection.onDispose()
		          .block();
	}
	
}

写入数据

要将数据发送到给定端点,必须附加一个I/O处理程序。I/O处理程序有权访问以NettyOutbound 能够写入数据

import reactor.core.publisher.Mono;
import reactor.netty.Connection;
import reactor.netty.tcp.TcpClient;

public class Application {

	public static void main(String[] args) {
		Connection connection =
				TcpClient.create()
				         .host("example.com")
				         .port(80)
                          // 将hello字符串发送到服务端点
				         .handle((inbound, outbound) -> outbound.sendString(Mono.just("hello"))) 
				         .connectNow();

		connection.onDispose()
		          .block();
	}
	
}

当需要更多地控制写入过程时,作为I/O处理程序的替代方案,可以使用Connection#outbound. 与在提供的Publisher完成时关闭连接的I/O处理程序相反(在finite的情况下Publisher),当使用时Connection#outbound,必须显式调用Connection#dispose以关闭连接。

import reactor.core.publisher.Mono;
import reactor.netty.Connection;
import reactor.netty.tcp.TcpClient;

public class Application {

	public static void main(String[] args) {
		Connection connection =
				TcpClient.create()
				         .host("example.com")
				         .port(80)
				         .connectNow();

		connection.outbound()
		          .sendString(Mono.just("hello 1")) // 将hello 1字符串发送到端点
		          .then()
		          .subscribe();

		connection.outbound()
		          .sendString(Mono.just("hello 2"))  // 将hello 2字符串发送到端点
		          .then()
		          .subscribe(null, null, connection::dispose);  // 将消息发送到端点后关闭连接

		connection.onDispose()
		          .block();
	}
	
}

消费数据

要从给定端点接收数据,必须附加一个I/O处理程序。I/O处理程序有权访问NettyInbound以读取数据

import reactor.netty.Connection;
import reactor.netty.tcp.TcpClient;

public class Application {

	public static void main(String[] args) {
		Connection connection =
				TcpClient.create()
				         .host("example.com")
				         .port(80)
                          // 从给定端点接收数据
				         .handle((inbound, outbound) -> inbound.receive().then())
				         .connectNow();

		connection.onDispose()
		          .block();
	}
	
}

当需要对读取过程进行更多控制时(在不同的地方进行不同的数据处理),作为I/O处理程序的替代方案,可以使用 Connection#inbound。与在提供的Publisher完成时关闭连接的 I/O 处理程序相反(在finite的情况下Publisher),当使用Connection#inbound时,必须显式调用Connection#dispose以关闭连接。

import reactor.netty.Connection;
import reactor.netty.tcp.TcpClient;

public class Application {

	public static void main(String[] args) {
		Connection connection =
				TcpClient.create()
				         .host("example.com")
				         .port(80)
				         .connectNow();

		connection.inbound()
		          .receive() // 从给定端点接收数据
		          .then()
		          .subscribe();

		connection.onDispose()
		          .block();
	}
	
}

生命周期回调

TcpClient提供了以下生命周期回调函数以便扩展

回调函数描述
doAfterResolve在成功解析远程地址后调用
doOnChannelInit初始化通道时调用
doOnConnect当通道即将连接时调用
doOnConnected在通道连接后调用
doOnDisconnected在通道断开连接后调用
doOnResolve在即将解析远程地址时调用
doOnResolveError在远程地址未成功解析的情况下调用

Option和childOption参数设置

Option和childOption参数设置(点击进入…)


TCP-level配置(三种配置)

(1)Channel Options:通道参数选项

默认情况下,TCP客户端配置有以下选项

this.config = new TcpClientConfig(
			provider,
			Collections.singletonMap(ChannelOption.AUTO_READ, false),
			() -> AddressUtils.createUnresolved(NetUtil.LOCALHOST.getHostAddress(), DEFAULT_PORT));

如果需要其他选项或需要更改当前选项,可以应用以下配置:

import io.netty.channel.ChannelOption;
import reactor.netty.Connection;
import reactor.netty.tcp.TcpClient;

public class Application {

	public static void main(String[] args) {
		Connection connection =
				TcpClient.create()
				         .host("example.com")
				         .port(80)
				         .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000)
				         .connectNow();

		connection.onDispose()
		          .block();
	}
	
}

(2)Wire Logger:连线日志记录

Reactor Netty支持3种不同的格式化程序:

连线日志格式化描述
AdvancedByteBufFormat#HEX_DUM同时记录事件和内容。内容将采用十六进制格式(默认)
AdvancedByteBufFormat#SIMPLE使用此格式启用连线记录时,仅记录事件
AdvancedByteBufFormat#TEXTUAL同时记录事件和内容。内容将采用纯文本格式
import reactor.netty.DisposableServer;
import reactor.netty.http.server.HttpServer;

public class Application {

	public static void main(String[] args) {
		DisposableServer server =
				HttpServer.create()
                           // 启用连线记录
				          .wiretap(true) 
				          .bindNow();

		server.onDispose()
		      .block();
	}
	
}

当需要更改默认格式化程序时,可以按如下方式进行配置:

import io.netty.handler.logging.LogLevel;
import reactor.netty.DisposableServer;
import reactor.netty.http.server.HttpServer;
import reactor.netty.transport.logging.AdvancedByteBufFormat;

public class Application {

	public static void main(String[] args) {
		DisposableServer server =
				HttpServer.create()
                           // 启用连线记录, AdvancedByteBufFormat#TEXTUAL用于打印内容。
				          .wiretap("logger-name", LogLevel.DEBUG, AdvancedByteBufFormat.TEXTUAL) 
				          .bindNow();

		server.onDispose()
		      .block();
	}
}

(3)Event Loop Group:事件循环组

默认情况下,TCP客户端使用“事件循环组”,其中工作线程的数量等于初始化时运行时可用的处理器数量(但最小值为4)。当需要不同的配置时,可以使用LoopResource#create方法之一

以下清单显示了事件循环组的默认配置:ReactorNetty.java

/**
*默认工作线程数,回退到可用处理器(但最小值为4)
 */
public static final String IO_WORKER_COUNT = "reactor.netty.ioWorkerCount";
/**
 *默认选择器线程计数,回退到-1(无选择器线程)
 */
public static final String IO_SELECT_COUNT = "reactor.netty.ioSelectCount";
/**
 *UDP的默认工作线程数,回退到可用处理器(但最小值为4
 */
public static final String UDP_IO_THREAD_COUNT = "reactor.netty.udp.ioThreadCount";
/**
 * 默认的静默期,保证不会发生对底层循环资源的处置,回退到2秒
 */
public static final String SHUTDOWN_QUIET_PERIOD = "reactor.netty.ioShutdownQuietPeriod";
/**
 * 默认情况下,无论任务是否在静默期内提交,在处理底层资源之前等待的最长时间为15秒。
 */
public static final String SHUTDOWN_TIMEOUT = "reactor.netty.ioShutdownTimeout";
/**
 * 默认值是否首选本机传输(epoll、kqueue),回退在可用时是否首选
 */
public static final String NATIVE = "reactor.netty.native";

如果需要更改这些设置,可以应用以下配置:

import reactor.netty.Connection;
import reactor.netty.resources.LoopResources;
import reactor.netty.tcp.TcpClient;

public class Application {

	public static void main(String[] args) {
		LoopResources loop = LoopResources.create("event-loop", 1, 4, true);

		Connection connection =
				TcpClient.create()
				         .host("example.com")
				         .port(80)
				         .runOn(loop)
				         .connectNow();

		connection.onDispose()
		          .block();
	}
	
}

连接池

默认情况下,Reactor Netty client(客户端)使用一个“固定”连接池,其中500个为活动通道的最大数量(Channel),1000个为允许保持挂起状态的进一步通道采集尝试的最大数量(对于其余配置,请检查下面的系统属性或构建器配置)。这意味着,如果有人试图获取一个通道,只要创建的通道少于500个,并且由池管理,那么实现就会创建一个新的通道。当达到池中通道的最大数量时,最多会延迟1000次获取通道的新尝试(挂起),直到通道再次返回到池中,并且会因错误而拒绝进一步尝试。

默认“固定”连接池
①500个为活动通道Channel)
②1000个为允许保持挂起状态的进一步通道采集尝试的最大数量

ReactorNetty.java

/**
默认最大连接数。退回到2个可用处理器(但最小值为16)
 */
public static final String POOL_MAX_CONNECTIONS = "reactor.netty.pool.maxConnections";
/**
 * 出错前的默认采集超时(毫秒)。如果-1在以无限制方式打开新连接之前,永远不会等待获取。后退45秒
 */
public static final String POOL_ACQUIRE_TIMEOUT = "reactor.netty.pool.acquireTimeout";
/**
 * 默认最大空闲时间,fallback -未指定最大空闲时间。
 */
public static final String POOL_MAX_IDLE_TIME = "reactor.netty.pool.maxIdleTime";
/**
 * 默认最大使用寿命,fallback -未指定最大使用寿命
 */
public static final String POOL_MAX_LIFE_TIME = "reactor.netty.pool.maxLifeTime";
/**
 *默认租赁策略(先进先出、后进先出),fallback - fifo
fifo-连接选择为先进先出
lifo -连接选择为后进先出
 */
public static final String POOL_LEASING_STRATEGY = "reactor.netty.pool.leasingStrategy";
/**
 * 与{@link SamplingAllocationStrategy}一起使用的默认{@code getpermitsamplingrate}(介于0d和1d(百分比)之间)。
此策略包装了一个{@link PoolBuilder#sizeBetween(int,int)sizeBetween}{@link AllocationStrategy},并对{@link AllocationStrategy#getpermissions(int)}的调用进行了示例。回退-未启用。
 */
public static final String POOL_GET_PERMITS_SAMPLING_RATE = "reactor.netty.pool.getPermitsSamplingRate";
/**
 * 与{@link SamplingLocationStrategy}一起使用的默认{@code returnPermitsSamplingRate}(介于0d和1d(百分比)之间)。
此策略包装了一个{@link PoolBuilder#sizeBetween(int,int)sizeBetween}{@link AllocationStrategy},并对{@link AllocationStrategy#returnpermissions(int)}的调用进行了示例。回退-未启用。
 */
public static final String POOL_RETURN_PERMITS_SAMPLING_RATE = "reactor.netty.pool.returnPermitsSamplingRate";

当需要更改默认设置时,可以进行ConnectionProvider如下配置:

import reactor.netty.Connection;
import reactor.netty.resources.ConnectionProvider;
import reactor.netty.tcp.TcpClient;
import java.time.Duration;

public class Application {

	public static void main(String[] args) {
		ConnectionProvider provider =
				ConnectionProvider.builder("fixed")
                                   // 最大连接数
				                  .maxConnections(50)
				                  // 将连接保持空闲的最长时间配置为 20 秒
				                  .maxIdleTime(Duration.ofSeconds(20))    
				                  // 将连接保持活动的最长时间配置为 60 秒
				                  .maxLifeTime(Duration.ofSeconds(60))    
				                  // 将挂起获取操作的最长时间配置为 60 秒       
				                  .pendingAcquireTimeout(Duration.ofSeconds(60)) 
				                  //每两分钟,将定期检查连接池中是否存在适用于删除的连接
				                  .evictInBackground(Duration.ofSeconds(120))    
				                  .build();

		Connection connection =
				TcpClient.create(provider)
				         .host("example.com")
				         .port(80)
				         .connectNow();

		connection.onDispose()
		          .block();
	}
	
}

当期望高负载时,请谨慎使用具有非常高的最大连接值的连接池。
reactor.netty.http.client.PrematureCloseException由于打开/获取的并发连接过多,可能会遇到 根本原因“连接超时”的异常。

需要禁用连接池,可以应用如下配置:

import reactor.netty.Connection;
import reactor.netty.tcp.TcpClient;

public class Application {

	public static void main(String[] args) {
		Connection connection =
				TcpClient.newConnection()
				         .host("example.com")
				         .port(80)
				         .connectNow();

		connection.onDispose()
		          .block();
	}
	
}

(1)disposeInactivePoolsInBackground:检查连接池

启用此选项后,会在后台定期检查连接池,那些在指定时间内为空且不活动的连接池将有资格进行处理。默认情况下,禁用非活动池的这种后台处理。

(2)disposeTimeout:处理超时

当ConnectionProvider#dispose()或ConnectionProvider#disposeLater()被调用时,使用此宽限期超时触发连接池的正常关闭。从那时起,所有获取连接的调用都会快速失败,但会出现异常。但是,对于所提供的Duration,待处理的获取将有机会得到服务。注:拒绝新的获取和计时器立即启动风度,不论认购到Mono的返回ConnectionProvider#disposeLater()。随后的调用返回相同的Mono,有效地从第一个正常关闭调用中获取通知并忽略随后提供的超时。默认情况下,不指定处理超时。

(3)evictInBackground:定期检查符合删除条件的连接

启用此选项后,每个连接池都会根据驱逐标准定期检查符合删除条件的连接maxIdleTime。默认情况下,此后台驱逐是禁用的。

(4)fifo:默认租赁策略 - 先进先出

配置连接池,如果有空闲连接(即池未充分利用),下一次获取操作将获取Least Recently Used连接(LRU,即当前空闲连接中最先释放的连接)。默认租赁策略。

(5)lifo:租赁策略 - 后进先出

配置连接池,如果有空闲连接(即池未充分利用),下一次获取操作将获取Most Recently Used连接(MRU,即当前空闲连接中最后释放的连接)。

(6)maxConnections:连接数

开始挂起之前的最大连接数(每个连接池)。默认:2 * 可用处理器数(但最小值为16)。

(7)maxIdleTime:最大空闲时间

空闲时通道可以关闭的时间(分辨率:ms)。默认值:未指定最大空闲时间。

(8)maxLifeTime:最大寿命

通道有资格关闭的总生命周期(分辨率:ms)。默认值:未指定最大寿命。

(9)metrics:监控指标

启用/禁用与Micrometer的内置集成。ConnectionProvider.MeterRegistrar可以提供与另一个度量系统的集成。默认情况下,metrics未启用。

(10)pendingAcquireMaxCount:挂起队列中的最大额外尝试次数

获取连接以保留在挂起队列中的最大额外尝试次数。如果指定 -1,则挂起队列没有上限。
默认:2 * 最大连接数。

(11)pendingAcquireTimeout:挂起获取必须完成或抛出TimeoutException之前的最长时间

挂起获取必须完成或抛出TimeoutException之前的最长时间(分辨率:毫秒)。如果指定了 -1,则不会应用此类超时。默认值:45秒。


Metrics(监控指标)

TCP客户端支持内置集成的Micrometer,公开了前缀为reactor.netty.connection.provider的所有指标

启用内置集成:

import reactor.netty.Connection;
import reactor.netty.tcp.TcpClient;

public class Application {

	public static void main(String[] args) {
		Connection connection =
				TcpClient.create()
				         .host("example.com")
				         .port(80)
				         .metrics(true)  // 启用与 Micrometer 的内置集成
				         .connectNow();

		connection.onDispose()
		          .block();
	}
	
}

当需要TCP客户端指标与系统集成时,Micrometer或者想提供自己的集成Micrometer,可以提供自己的指标记录器:

import reactor.netty.Connection;
import reactor.netty.channel.ChannelMetricsRecorder;
import reactor.netty.tcp.TcpClient;

import java.net.SocketAddress;
import java.time.Duration;

public class Application {

	public static void main(String[] args) {
		Connection connection =
				TcpClient.create()
				         .host("example.com")
				         .port(80)
				         // 启用 TCP 客户端指标并提供ChannelMetricsRecorder实现
				         .metrics(true, CustomChannelMetricsRecorder::new) 
				         .connectNow();

		connection.onDispose()
		          .block();
	}
	
}

(1)TCP客户端指标的信息

指标名称类型描述
reactor.netty.tcp.client.data.receivedDistributionSummary接收的数据量,以字节为单位
reactor.netty.tcp.client.data.sentDistributionSummary发送的数据量,以字节为单位
reactor.netty.tcp.client.errorsCounter发生的错误数
reactor.netty.tcp.client.tls.handshake.timeTimerTLS握手所花费的时间
reactor.netty.tcp.client.connect.timeTimer连接到远程地址所花费的时间
reactor.netty.tcp.client.address.resolverTimer解析地址所花费的时间

(2)ConnectionProvider指标

指标名称类型描述
reactor.netty.connection.provider.total.connectionsGauge所有连接数,活动或空闲
reactor.netty.connection.provider.active.connectionsGauge已成功获取且正在使用中的连接数
reactor.netty.connection.provider.max.connectionsGauge允许的最大活动连接数
reactor.netty.connection.provider.idle.connectionsGauge空闲连接数
reactor.netty.connection.provider.pending.connectionsGauge等待连接的请求数
reactor.netty.connection.provider.max.pending.connectionsGauge等待就绪连接时将排队的最大请求数

(3)ByteBufAllocator metrics(指标)

指标名称类型描述
reactor.netty.bytebuf.allocator.used.heap.memoryGauge堆内存的字节数
reactor.netty.bytebuf.allocator.used.direct.memoryGauge直接内存的字节数
reactor.netty.bytebuf.allocator.used.heap.arenasGauge堆区域的数量(当PooledByteBufAllocator)
reactor.netty.bytebuf.allocator.used.direct.arenasGauge直接竞技场的数量(当PooledByteBufAllocator)
reactor.netty.bytebuf.allocator.used.threadlocal.cachesGauge线程本地缓存的数量(当PooledByteBufAllocator)
reactor.netty.bytebuf.allocator.used.small.cache.sizeGauge小缓存的大小(当PooledByteBufAllocator)
reactor.netty.bytebuf.allocator.used.normal.cache.sizeGauge正常缓存的大小(当PooledByteBufAllocator)
reactor.netty.bytebuf.allocator.used.chunk.sizeGauge竞技场的块大小(当PooledByteBufAllocator)

EventLoop metrics(指标)

指标名称类型描述
reactor.netty.eventloop.pending.tasksGauge事件循环中待处理的任务数

Unix域套接字

TCP当使用本机传输时,客户端支持Unix域套接字(UDS)

import io.netty.channel.unix.DomainSocketAddress;
import reactor.netty.Connection;
import reactor.netty.tcp.TcpClient;

public class Application {

	public static void main(String[] args) {
		Connection connection =
				TcpClient.create()
                          // 指定DomainSocketAddress将被使用
				         .remoteAddress(() -> new DomainSocketAddress("/tmp/test.sock")) 
				         .connectNow();

		connection.onDispose()
		          .block();
	}
	
}

主机名解析

默认情况下,TcpClient使用Netty的域名查找机制异步解析域名。这是JVM内置阻塞解析器的替代方案。

当需要更改默认设置时,可以进行TcpClient如下配置:

import reactor.netty.Connection;
import reactor.netty.tcp.TcpClient;

import java.time.Duration;

public class Application {

	public static void main(String[] args) {
		Connection connection =
				TcpClient.create()
				         .host("example.com")
				         .port(80)
                          // 此解析器执行的每个 DNS 查询的超时将为 500 毫秒
				         .resolver(spec -> spec.queryTimeout(Duration.ofMillis(500))) 
				         .connectNow();

		connection.onDispose()
		          .block();
	}
	
}

有时,可能希望切换到JVM内置解析器。可以进行TcpClient如下配置:

import io.netty.resolver.DefaultAddressResolverGroup;
import reactor.netty.Connection;
import reactor.netty.tcp.TcpClient;

public class Application {

	public static void main(String[] args) {
		Connection connection =
				TcpClient.create()
				         .host("example.com")
				         .port(80)
                          // 	设置JVM内置解析器。
				         .resolver(DefaultAddressResolverGroup.INSTANCE) 
				         .connectNow();

		connection.onDispose()
		          .block();
	}
	
}

可用的配置:

(1)cacheMaxTimeToLive:缓存DNS资源记录的最大生存时间

缓存的DNS资源记录的最大生存时间(分辨率:秒)。如果DNS服务器返回的DNS资源记录的生存时间大于此最大生存时间,则此解析器将忽略来自DNS服务器的生存时间并使用此最大生存时间。默认为Integer.MAX_VALUE.

(2)cacheMinTimeToLive:缓存DNS资源记录的最小生存时间

缓存的DNS资源记录的最小生存时间(分辨率:秒)。如果DNS服务器返回的DNS资源记录的生存时间小于此最小生存时间,则此解析器将忽略来自DNS服务器的生存时间并使用此最小生存时间。默认值:0。

(3)cacheNegativeTimeToLive:失败DNS查询的缓存的生存时间

失败的DNS查询的缓存的生存时间(分辨率:秒)。默认值:0。

(4)completeOncePreferredResolved:解析器会在首选地址类型的所有查询完成后立即通知

启用此设置后,解析器会在首选地址类型的所有查询完成后立即通知。禁用此设置后,解析器会在所有可能的地址类型完成时发出通知。此配置适用于DnsNameResolver#resolveAll(String)。默认:启用

(5)disableOptionalRecord:禁用可选记录的自动包含

禁用可选记录的自动包含,该记录试图向远程DNS服务器提供有关解析器每个响应可以读取多少数据的提示。默认:启用。

(6)disableRecursionDesired:解析器是否必须发送设置了递归所需(RD)标志的DNS查询

指定此解析器是否必须发送设置了递归所需(RD)标志的DNS查询。默认:启用。

(7)hostsFileEntriesResolver:文件条目分解器

设置HostsFileEntriesResolver用于主机文件条目的自定义。默认值:DefaultHostsFileEntriesResolver。

(8)maxPayloadSize:数据报包缓冲区的容量

设置数据报包缓冲区的容量(以字节为单位)。默认值:4096 byte。

(9)maxQueriesPerResolve:解析主机名时允许发送的最大DNS查询数

设置解析主机名时允许发送的最大DNS查询数。默认值:16。

(10)ndots:初始绝对查询之前必须出现在名称中的点数

设置在进行初始绝对查询之前必须出现在名称中的点数。默认值:-1(确定来自Unix上的操作系统的值,否则使用值1)

(11)queryTimeout:解析器执行的每个DNS查询的超时时间

设置此解析器执行的每个DNS查询的超时时间(分辨率:毫秒)。默认值:5000。

(12)resolvedAddressTypes:解析地址的协议族列表

解析地址的协议族列表。

(13)bindAddressSupplier:本地地址的供应商

要绑定到的本地地址的供应商。

(14)roundRobinSelection:服务器地址的随机选择

启用DnsNameResolver的AddressResolver组,如果名称服务器提供多个地址,则该组支持随机选择目标地址。请参阅RoundRobinDnsAddressResolverGroup。默认值:DnsAddressResolverGroup

(15)runOn:在给定资源上执行与DNS服务器的通信

在给定资源上执行与DNS服务器的通信。默认情况下,将使用在客户端级别指定的LoopResources。

(16)searchDomains:解析器的搜索域列表

解析器的搜索域列表。默认情况下,使用系统DNS搜索域填充有效搜索域列表。

(17)trace:解析失败的情况下生成详细跟踪信息

在解析失败的情况下生成详细跟踪信息时,此解析器将使用的特定记录器和日志级别。

  • 21
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

未禾

您的支持是我最宝贵的财富!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值