Springboot中用 Netty 开启UDP服务

Netty

Netty是一种提供网络编程的工具,是对socket编程的一例优秀的包装,支持TCP、UDP、FTP等协议。我们可以用Netty开发自己的http服务器、udp服务器、FTP服务器,RPC服务器等
Netty大受欢迎的原因:

  1. 并发高
    Netty支持NIO编程,NIO的持支,可以大大提升并发性能。
  2. 传输快
    Netty NIO的一个特性是零拷贝,直接在内存中开辟一块,剩去了socket缓冲区,
  3. 封装好

接下来写一个简单的udp demo。大体思路:

  1. 写一个netty的 基于UDP的Server 用来接受数据
  2. 写个一处理类,用于对接受的数据进行处理,然后返回信息;

新建一个springboot项目。在pom中引入jar

pom.xml

        
       <!--springboot version 我用的是2.1.3.RELEASE-->
		 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <version>2.1.3.RELEASE</version>
        </dependency>
       
       <!--web模块的启动器 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>


        <!-- netty依赖 springboot2.x自动导入版本 -->
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
        </dependency>
        
		<!-- 这里我用到了@slf4j 所以引入这个jar -->
      <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

创建NettyUDPServer

Channel 通道的类型

  • NioSocketChannel, 代表异步的客户端 TCP Socket 连接.
  • NioServerSocketChannel, 异步的服务器端 TCP Socket 连接.
  • NioDatagramChannel, 异步的 UDP 连接
  • NioSctpChannel, 异步的客户端 Sctp 连接.
  • NioSctpServerChannel, 异步的 Sctp 服务器端连接.
  • OioSocketChannel, 同步的客户端 TCP Socket 连接.
  • OioServerSocketChannel, 同步的服务器端 TCP Socket 连接.
  • OioDatagramChannel, 同步的 UDP 连接
  • OioSctpChannel, 同步的 Sctp 服务器端连接.
  • OioSctpServerChannel, 同步的客户端 TCP Socket 连接.

Bootstrap 是 Netty 提供的一个便利的工厂类,可以通过它来完成 Netty 的客户端或服务器端的 Netty 初始化。

package com.demo.udpdemo.UDPServer;

import com.demo.udpdemo.handler.BootNettyUdpSimpleChannelInboundHandler;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioDatagramChannel;
import lombok.extern.slf4j.Slf4j;

/**
 * @author 
 */
@Slf4j
public class BootNettyUdpServer {

    /**
     * 启动服务
     */
    public void bind(int port) {

        log.info("-------------------------------udpServer-------------------------");
        //表示服务器连接监听线程组,专门接受 accept 新的客户端client 连接
        EventLoopGroup bossLoopGroup  = new NioEventLoopGroup();
        try {
            //1,创建netty bootstrap 启动类
            Bootstrap serverBootstrap = new Bootstrap();
            //2、设置boostrap 的eventLoopGroup线程组
            serverBootstrap = serverBootstrap.group(bossLoopGroup);
            //3、设置NIO UDP连接通道
            serverBootstrap = serverBootstrap.channel(NioDatagramChannel.class);
            //4、设置通道参数 SO_BROADCAST广播形式
            serverBootstrap = serverBootstrap.option(ChannelOption.SO_BROADCAST, true);
            //5、设置处理类 装配流水线
            serverBootstrap = serverBootstrap.handler(new BootNettyUdpSimpleChannelInboundHandler());
            //6、绑定server,通过调用sync()方法异步阻塞,直到绑定成功
            ChannelFuture f = serverBootstrap.bind(port).sync();

            log.info(BootNettyUdpServer.class.getName()+" started and listend on "+f.channel().localAddress());

            //7、监听通道关闭事件,应用程序会一直等待,直到channel关闭
            f.channel().closeFuture().sync();
        } catch (Exception e) {
            // TODO: handle exception
        } finally {
            System.out.println("netty udp close!");
            //8 关闭EventLoopGroup,
            bossLoopGroup.shutdownGracefully();
        }
    }
}

NettyUdpSimpleChannelInboundHandler

package com.demo.udpdemo.handler;

import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.socket.DatagramPacket;
import io.netty.util.CharsetUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * @author 
 */
@Slf4j
public class BootNettyUdpSimpleChannelInboundHandler extends SimpleChannelInboundHandler<DatagramPacket> {

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception {
        try {
            String strdata = msg.content().toString(CharsetUtil.UTF_8);
            //打印收到的消息
            log.info("---------------------receive data--------------------------");
            log.info(strdata);
            log.info("---------------------receive data--------------------------");
            //收到udp消息后,可通过此方式原路返回的方式返回消息,例如返回时间戳
            ctx.writeAndFlush(new DatagramPacket(Unpooled.copiedBuffer("ok", CharsetUtil.UTF_8), msg.sender()));
        } catch (Exception e) {

        }
    }

}

修改启动类,启动执行UDPServer.bind方法,启动udpServer

@SpringBootApplication
@EnableAsync
public class UdpDemoApplication implements CommandLineRunner {

    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(UdpDemoApplication.class);
        app.run(args);
    }

    @Async
    @Override
    public void run(String... args){
       new BootNettyUdpServer().bind(51000);
    }
}

test

在test类下面,新建一个test方法
sendUdpRequestTest

 	//定义客户端ip
 	private static final String SERVER_HOSTNAME = "127.0.0.1";
    // 服务器端口
    private static final int SERVER_PORT = 51000;
    // 本地发送端口
    private static final int LOCAL_PORT = 8888;

 @Test
    public void sendUdpRequestTest() {
        try {
            // 1,创建udp服务。通过DatagramSocket对象。
            DatagramSocket socket = new DatagramSocket(LOCAL_PORT);
            // 2,确定数据,并封装成数据包。DatagramPacket(byte[] buf, int length, InetAddress
            // address, int port)
            byte[] buf = "hello".getBytes();
            DatagramPacket dp = new DatagramPacket(buf, buf.length, InetAddress.getByName(SERVER_HOSTNAME),
                    SERVER_PORT);
            // 3,通过socket服务,将已有的数据包发送出去。通过send方法。
            socket.send(dp);
            // 4,关闭资源。
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

结果

2021-09-03 13:14:47.912  INFO 11608 --- [ntLoopGroup-2-1] .BootNettyUdpSimpleChannelInboundHandler : ---------------------receive data--------------------------
2021-09-03 13:14:47.912  INFO 11608 --- [ntLoopGroup-2-1] .BootNettyUdpSimpleChannelInboundHandler : 你好,世界
2021-09-03 13:14:47.912  INFO 11608 --- [ntLoopGroup-2-1] .BootNettyUdpSimpleChannelInboundHandler : ---------------------receive data--------------------------
2021-09-03 13:16:11.748  INFO 11608 --- [ntLoopGroup-2-1] .BootNettyUdpSimpleChannelInboundHandler : ---------------------receive data--------------------------
2021-09-03 13:16:11.748  INFO 11608 --- [ntLoopGroup-2-1] .BootNettyUdpSimpleChannelInboundHandler : 你好,世界
2021-09-03 13:16:11.748  INFO 11608 --- [ntLoopGroup-2-1] .BootNettyUdpSimpleChannelInboundHandler : ---------------------receive data--------------------------
2021-09-03 13:17:11.664  INFO 11608 --- [ntLoopGroup-2-1] .BootNettyUdpSimpleChannelInboundHandler : ---------------------receive data--------------------------
2021-09-03 13:17:11.664  INFO 11608 --- [ntLoopGroup-2-1] .BootNettyUdpSimpleChannelInboundHandler : hello
2021-09-03 13:17:11.664  INFO 11608 --- [ntLoopGroup-2-1] .BootNettyUdpSimpleChannelInboundHandler : ---------------------receive data--------------------------
2021-09-03 13:17:32.714  INFO 11608 --- [ntLoopGroup-2-1] .BootNettyUdpSimpleChannelInboundHandler : ---------------------receive data--------------------------
2021-09-03 13:17:32.714  INFO 11608 --- [ntLoopGroup-2-1] .BootNettyUdpSimpleChannelInboundHandler : hello
2021-09-03 13:17:32.714  INFO 11608 --- [ntLoopGroup-2-1] .BootNettyUdpSimpleChannelInboundHandler : ---------------------receive data--------------------------
  • 2
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是使用SpringBoot整合Netty实现UDP服务端的代码示例: 首先,在pom.xml文件中添加以下依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>io.netty</groupId> <artifactId>netty-transport-native-epoll</artifactId> <version>4.1.63.Final</version> <classifier>linux-x86_64</classifier> <scope>provided</scope> </dependency> <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.63.Final</version> </dependency> ``` 接下来,创建一个UDP服务器类,如下所示: ```java import io.netty.bootstrap.Bootstrap; import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.DatagramPacket; import io.netty.channel.socket.nio.NioDatagramChannel; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @Component public class UdpServer { @Value("${udp.port}") private int port; public void start() throws Exception { EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap bootstrap = new Bootstrap(); bootstrap.group(group) .channel(NioDatagramChannel.class) .option(ChannelOption.SO_BROADCAST, true) .handler(new ChannelInitializer<Channel>() { @Override protected void initChannel(Channel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new UdpServerHandler()); } }); ChannelFuture future = bootstrap.bind(port).sync(); future.channel().closeFuture().await(); } finally { group.shutdownGracefully(); } } } ``` 然后,创建一个UDP服务器处理程序类,如下所示: ```java import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.socket.DatagramPacket; public class UdpServerHandler extends SimpleChannelInboundHandler<DatagramPacket> { @Override protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) throws Exception { // 处理接收到的UDP数据包 String message = packet.content().toString(CharsetUtil.UTF_8); // 在这里进行业务处理 System.out.println("接收到UDP消息:" + message); } } ``` 最后,在Spring Boot的启动类中添加以下代码: ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Application implements CommandLineRunner { @Autowired private UdpServer udpServer; public static void main(String[] args) { SpringApplication.run(Application.class, args); } @Override public void run(String... args) throws Exception { udpServer.start(); } } ``` 现在,你可以在配置文件中指定UDP服务器的端口号(如application.properties或application.yml),然后运行Spring Boot应用程序来启动UDP服务器。 这样就实现了使用SpringBoot整合Netty实现UDP服务端的代码。你可以根据自己的需求进行进一步的业务处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值