springboot+netty实现UDP监听两个端口

本文介绍如何在SpringBoot项目中集成Netty框架来实现UDP通信,并演示了如何在启动时初始化两个UDP监听服务。包括NettyServerHandlerInitializer、SimpleChannelInboundHandler等组件的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在springboot工程中集成netty框架实现UDP通信,在CommandLineRunner的初始化启动时启动两个UDP监听服务。
实例如下
1、两个NettyUdpServer

@Slf4j
@Component
@EnableAsync
public class NettyUdpServer {

    @Autowired
    NettyServerHandlerInitializer nettyServerHandlerInitializer;

    @Async
    public void init(int port) {
        //表示服务器连接监听线程组,专门接受 accept 新的客户端client 连接
        EventLoopGroup bossLoopGroup = new NioEventLoopGroup();
        try {
            //1、创建netty bootstrap 启动类
            Bootstrap serverBootstrap = new Bootstrap();
            //2、设置boostrap 的eventLoopGroup线程组
            serverBootstrap.group(bossLoopGroup)
                    //3、设置NIO UDP连接通道
                    .channel(NioDatagramChannel.class)
                    // 设置 Netty Server 的端口
                    .localAddress(new InetSocketAddress(port))
                    //4、设置通道参数 SO_BROADCAST广播形式
                    .option(ChannelOption.SO_BROADCAST, true)
                    //5、设置处理类 装配流水线
                    .handler(nettyServerHandlerInitializer);
            //6、绑定server,通过调用sync()方法异步阻塞,直到绑定成功
            ChannelFuture channelFuture = serverBootstrap.bind().sync();
            log.info("started and listened on " + channelFuture.channel().localAddress());
            //7、监听通道关闭事件,应用程序会一直等待,直到channel关闭
            channelFuture.channel().closeFuture().sync();
        } catch (Exception e) {
        } finally {
            log.info("netty udp close!", "info");
            //8 关闭EventLoopGroup,
            bossLoopGroup.shutdownGracefully();
        }
    }
}
@Slf4j
@Component
@EnableAsync
public class NettyUdpServer2 {

    @Autowired
    NettyServerHandlerInitializer2 nettyServerHandlerInitializer2;

    @Async
    public void init(int port) {
        //表示服务器连接监听线程组,专门接受 accept 新的客户端client 连接
        EventLoopGroup bossLoopGroup = new NioEventLoopGroup();
        try {
            //1、创建netty bootstrap 启动类
            Bootstrap serverBootstrap = new Bootstrap();
            //2、设置boostrap 的eventLoopGroup线程组
            serverBootstrap.group(bossLoopGroup)
                    //3、设置NIO UDP连接通道
                    .channel(NioDatagramChannel.class)
                    // 设置 Netty Server 的端口
                    .localAddress(new InetSocketAddress(port))
                    //4、设置通道参数 SO_BROADCAST广播形式
                    .option(ChannelOption.SO_BROADCAST, true)
                    //5、设置处理类 装配流水线
                    .handler(nettyServerHandlerInitializer2);
            //6、绑定server,通过调用sync()方法异步阻塞,直到绑定成功
            ChannelFuture channelFuture = serverBootstrap.bind().sync();
            log.info("started and listened on " + channelFuture.channel().localAddress());
            //7、监听通道关闭事件,应用程序会一直等待,直到channel关闭
            channelFuture.channel().closeFuture().sync();
        } catch (Exception e) {
        } finally {
            log.info("netty udp close!", "info");
            //8 关闭EventLoopGroup,
            bossLoopGroup.shutdownGracefully();
        }
    }
}

2、CommandLineRunner启动

	...
	private void initNettyUdpServer() {
        nettyUdpServer.init(port);
        nettyUdpServer2.init(port2);
    }

启动监听两个端口。
3、ChannelInitializer

@Component
public class NettyServerHandlerInitializer extends ChannelInitializer<Channel> {

    @Autowired
    NettyHandler nettyHandler;

    @Override
    protected void initChannel(Channel channel) {
        ChannelPipeline channelPipeline = channel.pipeline();
        // 添加一堆 NettyServerHandler 到 ChannelPipeline 中
        channelPipeline.addLast("nettyHandler", nettyHandler);
    }
}

4、SimpleChannelInboundHandler

@Slf4j
@Component
public class NettyHandler extends SimpleChannelInboundHandler<DatagramPacket> {

    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, DatagramPacket datagramPacket) throws Exception {
        ByteBuf byteBuf = datagramPacket.content();
        byte[] bytes = new byte[byteBuf.readableBytes()];
        byteBuf.readBytes(bytes);
        //数据处理

        // res
        String resStr = "ok";
        byte[] resBytes = resStr.getBytes(StandardCharsets.UTF_8);
        DatagramPacket resData = new DatagramPacket(Unpooled.copiedBuffer(resBytes), datagramPacket.sender());
        channelHandlerContext.writeAndFlush(resData);
    }
}

5、测试
启动服务,结果类似如下
在这里插入图片描述
可见启动了两个upd端口监听。
6、UDP测试的服务端和客户端
下面为基于netty的UDP服务端用于监听和基于netty的UDP客户端用于发送

public class UdpServer {
 
    public static void main(String[] args) throws InterruptedException {
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group)
                    // 主线程处理
                    .channel(NioDatagramChannel.class)
                    // 广播
                    .option(ChannelOption.SO_BROADCAST, true)
                    // 设置读缓冲区为2M
                    .option(ChannelOption.SO_RCVBUF, 2048 * 1024)
                    // 设置写缓冲区为1M
                    .option(ChannelOption.SO_SNDBUF, 1024 * 1024)
                    .handler(new ChannelInitializer<NioDatagramChannel>() {
                        @Override
                        protected void initChannel(NioDatagramChannel ch) {
                            ChannelPipeline pipeline = ch.pipeline();
                            pipeline.addLast(new NioEventLoopGroup(), new UdpServerHandler());
                        }
                    });
            ChannelFuture f = bootstrap.bind(8000).sync();
            System.out.println("服务器正在监听......");
            f.channel().closeFuture().sync();
        } finally {
            group.shutdownGracefully();
        }
 
    }
}
public class UdpServerHandler extends SimpleChannelInboundHandler<DatagramPacket> {
 
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) {
        System.out.println("服务端接收到消息:" + packet.content().toString(StandardCharsets.UTF_8));
        // 向客户端回复消息
        ByteBuf byteBuf = Unpooled.copiedBuffer("已经接收到消息!".getBytes(StandardCharsets.UTF_8));
        ctx.writeAndFlush(new DatagramPacket(byteBuf, packet.sender()));
    }
}
public class UdpClient {
 
    public static void main(String[] args) {
    EventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group)
                    .channel(NioDatagramChannel.class)
                    .handler(new ChannelInitializer<NioDatagramChannel>() {
                        @Override
                        protected void initChannel(NioDatagramChannel ch) {
                            ChannelPipeline pipeline = ch.pipeline();
                            pipeline.addLast(new UdpClientHandler());
                        }
                    });
            Channel channel = bootstrap.bind(8089).sync().channel();
            InetSocketAddress address = new InetSocketAddress("localhost", 8088);
            ByteBuf byteBuf = Unpooled.copiedBuffer("你好".getBytes(StandardCharsets.UTF_8));
            channel.writeAndFlush(new DatagramPacket(byteBuf, address)).sync();
            channel.closeFuture().await();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            group.shutdownGracefully();
        }
    }
}
public class UdpClientHandler extends SimpleChannelInboundHandler<DatagramPacket> {
 
    protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) {
        System.out.println("客户端接收到消息:" + packet.content().toString(StandardCharsets.UTF_8));
        // 向服务端回复消息
        ByteBuf byteBuf = Unpooled.copiedBuffer("已经接收到消息!".getBytes(StandardCharsets.UTF_8));
        ctx.writeAndFlush(new DatagramPacket(byteBuf, packet.sender()));
    }
 
}

注:启动两个端口监听时需要采用@Async注解,使其异步执行,否则会出现只能启动第一个,第二个无法执行的问题。从日志中也只能看到第一个端口的监听,第二个没有执行

要在Spring Boot中使用Netty监听多个UDP端口,可以按照以下步骤: 1. 导入NettySpring Boot的依赖 ```xml <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.52.Final</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> ``` 2. 创建UDP服务器的配置类 ```java @Configuration public class UdpServerConfig { @Value("${udp.server.port}") private int port; @Value("${udp.server2.port}") private int port2; @Bean(name = "udpServer") public DatagramChannel udpServer() throws Exception { EventLoopGroup group = new NioEventLoopGroup(); DatagramChannel channel = DatagramChannel.open(); channel.bind(new InetSocketAddress(port)); channel.configureBlocking(false); channel.register(group, SelectionKey.OP_READ); return channel; } @Bean(name = "udpServer2") public DatagramChannel udpServer2() throws Exception { EventLoopGroup group = new NioEventLoopGroup(); DatagramChannel channel = DatagramChannel.open(); channel.bind(new InetSocketAddress(port2)); channel.configureBlocking(false); channel.register(group, SelectionKey.OP_READ); return channel; } @PreDestroy public void destroy() { udpServer().close(); udpServer2().close(); } } ``` 该配置类中创建了两个UDP服务器,分别监听不同的端口。其中,通过`@Value`注解注入了端口号,这里使用了`udp.server.port`和`udp.server2.port`两个属性。 3. 创建UDP服务器的处理类 ```java @Component public class UdpServerHandler implements ChannelInboundHandler { @Autowired @Qualifier("udpServer") private DatagramChannel udpServer; @Autowired @Qualifier("udpServer2") private DatagramChannel udpServer2; @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { DatagramPacket packet = (DatagramPacket) msg; // TODO: 处理UDP消息 } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); } } ``` 该类中注入了之前创建的两个UDP服务器,通过`channelRead`方法处理UDP消息。这里使用了`@Component`注解将该类交由Spring管理。 4. 配置Spring Boot应用的属性 在`application.properties`中配置UDP服务器的端口号: ```properties udp.server.port=8888 udp.server2.port=9999 ``` 5. 启动Spring Boot应用 在Spring Boot应用启动时,Netty将会自动创建两个UDP服务器,分别监听`8888`和`9999`端口。可以在`UdpServerHandler`类中编写UDP消息的处理逻辑。
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值