import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.util.CharsetUtil;
import lombok.SneakyThrows;
import java.net.InetSocketAddress;
public class BootNettyUdpClient {
private int port;
private String server;
public BootNettyUdpClient(String server,int port){
this.server = server;
this.port = port;
}
@SneakyThrows
public void send(String data) {
data = AES.encryptAES(data);
EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
try {
Bootstrap clientBootstrap = new Bootstrap();
clientBootstrap = clientBootstrap.group(eventLoopGroup);
clientBootstrap = clientBootstrap.channel(NioDatagramChannel.class);
clientBootstrap = clientBootstrap.option(ChannelOption.SO_BROADCAST, true);
clientBootstrap = clientBootstrap.handler(new BootNettyUdpClientSimpleChannelInboundHandler());
Channel channel = clientBootstrap.bind(0).sync().channel();
channel.writeAndFlush(new DatagramPacket(
Unpooled.copiedBuffer(data, CharsetUtil.UTF_8),
new InetSocketAddress(server,port)));
System.out.println("channnel id = "+channel.id().toString());
channel.closeFuture().await();
} catch (Exception e) {
// TODO: handle exception
} finally {
System.out.println("netty client udp close!");
eventLoopGroup.shutdownGracefully();
}
}
}
在你提供的
BootNettyUdpClient类中,send方法每次调用都会创建一个新的EventLoopGroup、Bootstrap实例,并且绑定一个新的Channel到一个临时的本地端口(通过bind(0)),然后发送数据包。这种设计有几个问题,其中最主要的是每次发送都会启动一个新的 Netty 客户端实例,并且在发送完数据后等待这个客户端实例关闭(channel.closeFuture().await();)。这就是为什么你只能发送一次数据,并且再次调用
send方法时会阻塞:资源消耗:每次发送都创建和销毁大量的 Netty 组件,这是非常低效的。
阻塞:
channel.closeFuture().await();会阻塞当前线程,直到这个Channel关闭。由于你在发送完数据后立即关闭了Channel,所以这个方法调用会等待直到 Netty 完成所有的清理工作。这意味着在send方法返回之前,不会有其他数据被发送。无法重用连接:UDP 本身是无连接的协议,但 Netty 的
DatagramPacket允许你在同一个Channel上发送多个数据包到不同的目标地址。然而,你的代码每次都会创建一个新的Channel,因此无法重用之前的连接(尽管 UDP 实际上没有“连接”的概念,但这里指的是 Netty 的Channel实例)。为了解决这个问题,你可以考虑以下方案:
重用
EventLoopGroup和Channel:将EventLoopGroup和Channel的创建移到BootNettyUdpClient类的构造函数或某个初始化方法中,然后在send方法中只使用这些已经创建好的资源来发送数据。移除
channel.closeFuture().await();:由于你不需要等待客户端关闭,可以直接发送数据后返回。Netty 会自动管理Channel的生命周期,特别是在使用无连接的 UDP 协议时。下面是一个简化的示例,展示了如何修改你的代码以重用
EventLoopGroup和Channel:在这个修改后的版本中,
EventLoopGroup和Channel只在构造函数中创建一次,并且提供了一个shutdown方法来优雅地关闭这些资源。现在你可以多次调用send方法来发送数据,而不会遇到阻塞或资源耗尽的问题。记得在不再需要客户端时调用shutdown方法来释放资源。