package org.springblade.modules.netty.server; import io.netty.bootstrap.Bootstrap; import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioDatagramChannel; import io.netty.handler.codec.LengthFieldBasedFrameDecoder; import io.netty.util.concurrent.DefaultEventExecutorGroup; import io.netty.util.concurrent.EventExecutorGroup; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springblade.modules.netty.config.MyDecoder; import org.springblade.modules.netty.handle.UdpServerHandler; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; /** * updServer udp服务端 * * @author zhongrj * @date 2023-02-21 */ @Component public class UdpServer { private static Logger LOG = LoggerFactory.getLogger(UdpServer.class); //给管道抽象出接口,给Channel更多的能力和配置,例如Channel的状态,参数,IO操作 //使用ChannelPipeline实现自定义IO //Channel channel; @Async("taskExecutor") public void run(int port) { //启动服务 EventLoopGroup workerGroup = new NioEventLoopGroup(); //优化使用的线程 final EventExecutorGroup group = new DefaultEventExecutorGroup(16); try { //udp不能使用ServerBootstrap Bootstrap b = new Bootstrap(); //设置UDP通道 b.group(workerGroup).channel(NioDatagramChannel.class) //设置udp的管道工厂 .handler(new ChannelInitializer() { //NioDatagramChannel标志着是UDP格式的 @Override protected void initChannel(NioDatagramChannel ch) throws Exception { // TODO Auto-generated method stub //创建一个执行Handler的容器 ChannelPipeline pipeline = ch.pipeline(); // pipeline.addLast(new StringDecoder()); pipeline.addLast("decoder",new MyDecoder()); // pipeline.addLast(new StringEncoder()); pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 4, 4, -8, 0)); //执行具体的自定义处理器 pipeline.addLast(group, "handler", new UdpServerHandler()); } })//初始化处理器 //true / false 多播模式(UDP适用),可以向多个主机发送消息 .option(ChannelOption.SO_BROADCAST, true) // 设置UDP读缓冲区为2M .option(ChannelOption.SO_RCVBUF, 2048 * 1024) // 设置UDP写缓冲区为1M .option(ChannelOption.SO_SNDBUF, 1024 * 1024); // 绑定端口,开始接收进来的连接 ChannelFuture f = b.bind(port).sync(); //获取channel通道 System.out.println("UDP Server 启动,端口:" + port); // 等待服务器 socket 关闭 。 // 这不会发生,可以优雅地关闭服务器。 f.channel().closeFuture().sync(); } catch (InterruptedException e) { e.printStackTrace(); } finally { //优雅退出 释放线程池资源 group.shutdownGracefully(); workerGroup.shutdownGracefully(); } } }