通过
webflux
,你可以快速搭建一个基于Reactor Netty或其他反应式运行时(如Tomcat, Jetty)的Web应用,并利用Spring Framework提供的全套功能,包括路由处理、数据绑定、验证、模板引擎等。
1、引入Jar包
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<!-- Reactor Netty for UDP support -->
<dependency>
<groupId>io.projectreactor.netty</groupId>
<artifactId>reactor-netty</artifactId>
</dependency>
</dependencies>
2、实现UDP服务配置
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import reactor.netty.DisposableServer;
import reactor.netty.udp.UdpServer;
import java.time.Duration;
import java.util.function.Consumer;
@Configuration
public class UdpServerConfig {
//你的ip和port
private final String host = "localhost";
private final int port = 9000;
// 自定义了这个解码器
private final UdpDecoderHandler udpDecoderHandler = new UdpDecoderHandler();
@Bean
public DisposableServer udpServer() {
return UdpServer.create()
.host(host)
.port(port)
.handle((in, out) -> in.receive()
.asByteArray()
.doOnNext(data -> handleUdpData(data)) // 处理接收到的数据
.then()) // 完成流后关闭连接(对于UDP来说通常不需要)
.doOnBound(conn -> conn.addHandlerLast("decoder", udpDecoderHandler))
.bindNow(Duration.ofSeconds(30));
}
private void handleUdpData(byte[] data) {
// 在这里处理你的UDP数据
System.out.println("Received UDP data: " + new String(data));
}
}
3、自定义解码器
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageDecoder;
import io.netty.util.ReferenceCountUtil;
import reactor.core.publisher.Flux;
import java.net.InetSocketAddress;
import java.util.List;
public class UdpDecoderHandler extends MessageToMessageDecoder<DatagramPacket> {
// 解码器实现,继承自MessageToMessageDecoder<DatagramPacket>
@Override
protected void decode(ChannelHandlerContext ctx, DatagramPacket datagramPacket, List<Object> out) throws Exception {
// 获取DatagramPacket中的ByteBuf数据部分,不进行复制以提高性能
ByteBuf content = datagramPacket.content();
// 创建一个新的自定义对象,包含原始数据和源地址信息
CustomUdpMessage message = new CustomUdpMessage(content.copy(), datagramPacket.sender());
// 将解码后的消息添加到输出列表中,供后续处理器使用
out.add(message);
// 释放原始的DatagramPacket资源,防止内存泄漏
ReferenceCountUtil.release(datagramPacket);
}
// 自定义UDP消息类,包含原始数据和发送者的地址信息
public static class CustomUdpMessage {
private final ByteBuf data; // 使用ByteBuf而不是字节数组,避免不必要的数据复制
private final InetSocketAddress sender;
// 构造函数,将ByteBuf内容和发送者地址保存为实例变量
public CustomUdpMessage(ByteBuf data, InetSocketAddress sender) {
this.data = data;
this.sender = sender;
}
// 提供获取数据的方法,但通常在处理时直接操作ByteBuf会更高效
public ByteBuf getData() {
return data;
}
// 获取发送者地址
public InetSocketAddress getSender() {
return sender;
}
// 在完成对CustomUdpMessage的处理后,记得释放其中包含的ByteBuf资源
public void releaseData() {
data.release();
}
}
}