6.Netty UDP客户端搭建(UdpClient),UdpClient生命周期回调,连接配置,Metrics(指标监控)

目录


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


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参数设置

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.receivedDistributionSummary接收的数据量,以字节为单位
reactor.netty.udp.client.data.sentDistributionSummary发送的数据量,以字节为单位
reactor.netty.udp.client.errorsCounter发生的错误数
reactor.netty.udp.client.connect.timeTimer连接到远程地址所花费的时间
reactor.netty.udp.client.address.resolverTimer解析地址所花费的时间

(2)ByteBufAllocator指标

metric名称类型描述
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)

(3)EventLoop指标

metric名称类型描述
reactor.netty.eventloop.pending.tasksGauge事件循环中待处理的任务数
Netty是一个高性能、异步事件驱动的网络应用程序框架,它支持多种传输协议,包括TCP、UDP、HTTP、WebSocket等。 下面是一个简单的Netty UDP客户端的示例代码: ```java public class UdpClient { public static void main(String[] args) throws Exception { // 创建 Bootstrap 对象 Bootstrap bootstrap = new Bootstrap(); // 设置 EventLoopGroup 对象 EventLoopGroup group = new NioEventLoopGroup(); try { // 配置 Bootstrap 对象 bootstrap.group(group) .channel(NioDatagramChannel.class) .option(ChannelOption.SO_BROADCAST, true) .handler(new UdpClientHandler()); // 绑定端口并启动客户端 Channel channel = bootstrap.bind(0).sync().channel(); // 发送数据 channel.writeAndFlush(new DatagramPacket( Unpooled.copiedBuffer("Hello, Netty UDP", CharsetUtil.UTF_8), new InetSocketAddress("255.255.255.255", 8080))).sync(); // 等待关闭 channel.closeFuture().await(); } finally { // 关闭 EventLoopGroup 对象 group.shutdownGracefully(); } } } class UdpClientHandler extends SimpleChannelInboundHandler<DatagramPacket> { @Override protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception { // 接收到响应数据 ByteBuf buf = msg.content(); System.out.println(buf.toString(CharsetUtil.UTF_8)); } } ``` 此示例中,我们创建了一个Bootstrap对象,设置了NioEventLoopGroup和UDP通道,然后绑定端口并发送数据。我们还定义了一个UdpClientHandler类来处理接收到的响应数据。 在发送数据时,我们使用DatagramPacket对象指定要发送的数据和目标地址。在接收响应数据时,我们使用SimpleChannelInboundHandler类的channelRead0()方法来处理接收到的数据。 这只是一个简单的示例,你可以根据需要自定义Netty UDP客户端的行为。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

未禾

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

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

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

打赏作者

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

抵扣说明:

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

余额充值