Springboot中用 Netty 开启UDP服务方式
目录
- Netty
- 新建一个springboot项目。在pom中引入jar
- 创建NettyUDPServer
- NettyUdpSimpleChannelInboundHandler
- 修改启动类,启动执行UDPServer.bind方法,启动udpServer
- test
- 结果
Netty
Netty是一种提供网络编程的工具,是对socket编程的一例优秀的包装,支持TCP、UDP、FTP等协议。我们可以用Netty开发自己的http服务器、udp服务器、FTP服务器,RPC服务器等
Netty大受欢迎的原因:
- 并发高
Netty支持NIO编程,NIO的持支,可以大大提升并发性能。
- 传输快
Netty NIO的一个特性是零拷贝,直接在内存中开辟一块,剩去了socket缓冲区,
- 封装好
接下来写一个简单的udp demo。大体思路:
- 写一个netty的 基于UDP的Server 用来接受数据
- 写个一处理类,用于对接受的数据进行处理,然后返回信息
新建一个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--------------------------
以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。