目录
Netty UDP客户端(UdpClient)
Reactor Netty提供了易于使用和易于配置的UdpClient。它隐藏了创建UDP客户端所需的大部分Netty功能,并添加了Reactive Streams背压(Reactive Streams是具有无阻塞背压的异步流处理的标准)
连接和断开
要将UDP客户端连接到给定端点,必须创建和配置UdpClient实例
默认情况下,主机配置localhost、端口12012
返回的Connection提供了一个简单的连接 API,连接到主机为example.com,端口为80;包括disposeNow(),它以阻塞方式关闭客户端。
import reactor.netty.Connection;
import reactor.netty.udp.UdpClient;
import java.time.Duration;
public class Application {
public static void main(String[] args) {
Connection connection =
UdpClient.create() // 创建一个UdpClient准备好配置的实例
.host("example.com") // 配置host此客户端应连接到的
.port(80) // 配置port此客户端应连接到的
// 以阻塞方式连接客户端并等待它完成初始化
.connectNow(Duration.ofSeconds(30));
connection.onDispose()
.block();
}
}
当需要预加载这些资源时,可以进行UdpClient如下配置:
import reactor.core.publisher.Mono;
import reactor.netty.Connection;
import reactor.netty.udp.UdpClient;
import java.time.Duration;
public class Application {
public static void main(String[] args) {
UdpClient udpClient = UdpClient.create()
.host("example.com")
.port(80)
.handle((udpInbound, udpOutbound) -> udpOutbound.sendString(Mono.just("hello")));
udpClient.warmup() // 初始化并加载事件循环组、主机名解析器和本机传输库
.block();
// 连接到远程对等方时发生主机名解析
Connection connection = udpClient.connectNow(Duration.ofSeconds(30));
connection.onDispose()
.block();
}
}
写入数据
要将数据发送到给定的对等方,必须附加一个I/O处理程序。I/O处理程序有权访问UdpOutbound,以便能够写入数据
import reactor.core.publisher.Mono;
import reactor.netty.Connection;
import reactor.netty.udp.UdpClient;
import java.time.Duration;
public class Application {
public static void main(String[] args) {
Connection connection =
UdpClient.create()
.host("example.com")
.port(80)
// 将hello字符串发送到远程对等方
.handle((udpInbound, udpOutbound) ->
udpOutbound.sendString(Mono.just("hello")
)
.connectNow(Duration.ofSeconds(30));
connection.onDispose()
.block();
}
}
消费数据
要从给定的对等方接收数据,必须附加一个I/O处理程序。I/O处理程序有权访问UdpInbound,以便能够读取数据
消费数据:
import reactor.netty.Connection;
import reactor.netty.udp.UdpClient;
import java.time.Duration;
public class Application {
public static void main(String[] args) {
Connection connection =
UdpClient.create()
.host("example.com")
.port(80)
// 从给定的对等方接收数据
.handle((udpInbound, udpOutbound) -> udpInbound.receive().then())
.connectNow(Duration.ofSeconds(30));
connection.onDispose()
.block();
}
}
生命周期回调
提供了以下生命周期回调以扩展UdpClient:
回调函数 | 描述 |
---|---|
doAfterResolve | 在成功解析远程地址后调用 |
doOnChannelInit | 初始化通道时调用 |
doOnConnect | 当通道即将连接时调用 |
doOnConnected | 在通道连接后调用 |
doOnDisconnected | 在通道断开连接后调用 |
doOnResolve | 在即将解析远程地址时调用 |
doOnResolveError | 在远程地址未成功解析的情况下调用 |
使用doOnConnected和doOnChannelInit回调:
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.logging.LoggingHandler;
import reactor.netty.Connection;
import reactor.netty.udp.UdpClient;
import java.time.Duration;
public class Application {
public static void main(String[] args) {
Connection connection =
UdpClient.create()
.host("example.com")
.port(80)
// NettyLineBasedFrameDecoder当通道被连接时,管道被扩展
.doOnConnected(conn -> conn.addHandler(new LineBasedFrameDecoder(8192)))
// Netty管道LoggingHandle在初始化通道时扩展
.doOnChannelInit((observer, channel, remoteAddress) ->
channel.pipeline()
.addFirst(new LoggingHandler("reactor.netty.examples")))
.connectNow(Duration.ofSeconds(30));
connection.onDispose()
.block();
}
}
Option和childOption参数设置
连接配置
(1)Channel Options:通道参数配置
默认情况下,UDP客户端配置有以下选项:
UdpClientConnect() {
this.config = new UdpClientConfig(
ConnectionProvider.newConnection(),
Collections.singletonMap(ChannelOption.AUTO_READ, false),
() -> new InetSocketAddress(NetUtil.LOCALHOST, DEFAULT_PORT));
}
如果需要附加选项或需要更改当前选项,可以应用以下配置:
import io.netty.channel.ChannelOption;
import reactor.netty.Connection;
import reactor.netty.udp.UdpClient;
import java.time.Duration;
public class Application {
public static void main(String[] args) {
Connection connection =
UdpClient.create()
.host("example.com")
.port(80)
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000)
.connectNow(Duration.ofSeconds(30));
connection.onDispose()
.block();
}
}
(2)Wire Logger:连线日志记录
Reactor Netty 提供线路日志记录,用于何时需要检查对等点之间的流量。默认情况下,线路日志记录处于禁用状态。要启用它,必须将记录器reactor.netty.udp.UdpClient级别设置为DEBUG并应用以下配置:
import reactor.netty.Connection;
import reactor.netty.udp.UdpClient;
import java.time.Duration;
public class Application {
public static void main(String[] args) {
Connection connection =
UdpClient.create()
.host("example.com")
.port(80)
.wiretap(true) // 启用连线记录
.connectNow(Duration.ofSeconds(30));
connection.onDispose()
}
}
当需要更改默认格式化程序时,可以按如下方式进行配置:
import io.netty.handler.logging.LogLevel;
import reactor.netty.Connection;
import reactor.netty.transport.logging.AdvancedByteBufFormat;
import reactor.netty.udp.UdpClient;
import java.time.Duration;
public class Application {
public static void main(String[] args) {
Connection connection =
UdpClient.create()
.host("example.com")
.port(80)
// 启用连线记录, AdvancedByteBufFormat#TEXTUAL用于打印内容
.wiretap("logger-name", LogLevel.DEBUG, AdvancedByteBufFormat.TEXTUAL)
.connectNow(Duration.ofSeconds(30));
}
}
Wire Logger格式化程序
Reactor Netty支持3种不同的格式化程序:
连线日志格式化 | 描述 |
---|---|
AdvancedByteBufFormat#HEX_DUM | 同时记录事件和内容。内容将采用十六进制格式(默认) |
AdvancedByteBufFormat#SIMPLE | 使用此格式启用连线记录时,仅记录事件 |
AdvancedByteBufFormat#TEXTUAL | 同时记录事件和内容。内容将采用纯文本格式 |
(3)Event Loop Group:事件循环组
默认情况下,UDP客户端使用“事件循环组”,其中工作线程的数量等于初始化时运行时可用的处理器数量(但最小值为4)。当需要不同的配置时,可以使用其中一种LoopResources#create()
默认配置:
/**
* 默认工作线程数,回退到可用处理器(但最小值为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.udp.UdpClient;
import java.time.Duration;
public class Application {
public static void main(String[] args) {
LoopResources loop = LoopResources.create("event-loop", 1, 4, true);
Connection connection =
UdpClient.create()
.host("example.com")
.port(80)
.runOn(loop)
.connectNow(Duration.ofSeconds(30));
connection.onDispose()
.block();
}
}
Metrics(指标监控)
UDP客户端支持与Micrometer。它公开了前缀为reactor.netty.udp.client的所有指标
启用该集成
import reactor.netty.Connection;
import reactor.netty.udp.UdpClient;
import java.time.Duration;
public class Application {
public static void main(String[] args) {
Connection connection =
UdpClient.create()
.host("example.com")
.port(80)
.metrics(true) // 启用与Micrometer的内置集成
.connectNow(Duration.ofSeconds(30));
connection.onDispose()
.block();
}
}
当需要UDP客户端指标与系统集成时,Micrometer或者想提供自己的集成Micrometer,可以提供自己的指标记录器:
import reactor.netty.Connection;
import reactor.netty.channel.ChannelMetricsRecorder;
import reactor.netty.udp.UdpClient;
import java.net.SocketAddress;
import java.time.Duration;
public class Application {
public static void main(String[] args) {
Connection connection =
UdpClient.create()
.host("example.com")
.port(80)
// 启用UDP客户端指标并提供ChannelMetricsRecorder实现
.metrics(true, CustomChannelMetricsRecorder::new)
.connectNow(Duration.ofSeconds(30));
connection.onDispose()
.block();
}
}
(1)UDP客户端指标的信息
metric名称 | 类型 | 描述 |
---|---|---|
reactor.netty.udp.client.data.received | DistributionSummary | 接收的数据量,以字节为单位 |
reactor.netty.udp.client.data.sent | DistributionSummary | 发送的数据量,以字节为单位 |
reactor.netty.udp.client.errors | Counter | 发生的错误数 |
reactor.netty.udp.client.connect.time | Timer | 连接到远程地址所花费的时间 |
reactor.netty.udp.client.address.resolver | Timer | 解析地址所花费的时间 |
(2)ByteBufAllocator指标
metric名称 | 类型 | 描述 |
---|---|---|
reactor.netty.bytebuf.allocator.used.heap.memory | Gauge | 堆内存的字节数 |
reactor.netty.bytebuf.allocator.used.direct.memory | Gauge | 直接内存的字节数 |
reactor.netty.bytebuf.allocator.used.heap.arenas | Gauge | 堆区域的数量(当PooledByteBufAllocator) |
reactor.netty.bytebuf.allocator.used.direct.arenas | Gauge | 直接竞技场的数量(当PooledByteBufAllocator) |
reactor.netty.bytebuf.allocator.used.threadlocal.caches | Gauge | 直接竞技场的数量(当PooledByteBufAllocator) |
reactor.netty.bytebuf.allocator.used.small.cache.size | Gauge | 小缓存的大小(当PooledByteBufAllocator) |
reactor.netty.bytebuf.allocator.used.normal.cache.size | Gauge | 正常缓存的大小(当PooledByteBufAllocator) |
reactor.netty.bytebuf.allocator.used.chunk.size | Gauge | 竞技场的块大小(当PooledByteBufAllocator) |
(3)EventLoop指标
metric名称 | 类型 | 描述 |
---|---|---|
reactor.netty.eventloop.pending.tasks | Gauge | 事件循环中待处理的任务数 |