UDP是一个无连接协议,应用范围很大,对于一些低功耗的设备可以使用UDP方式向云端推送消息信息,也可以在推送消息时收到从云端原路返回的消息,使用Netty+SpringBoot方式可以快速开发一套基于UDP协议的服务端程序。
1、 新建Springboot的maven项目,pom.xml文件导入依赖包
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.6.RELEASE</version> <relativePath /> <!-- lookup parent from repository --> </parent> <dependencies> <!--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> </dependencies>
2、Springboot启动类,使用异步方式启动一个基于UDP协议的Netty应用(也包含web应用的)
package boot.netty.udp; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.EnableAsync; @SpringBootApplication @EnableAsync public class BootNettyUdpApplication implements CommandLineRunner{ public static void main( String[] args ) { /** * 启动springboot */ SpringApplication app = new SpringApplication(BootNettyUdpApplication.class); app.run(args); System.out.println( "Hello World!" ); } @Async @Override public void run(String... args) throws Exception { /** * 使用异步注解方式启动netty udp服务端服务 */ new BootNettyUdpServer().bind(9999); } }
3、Netty的UDP启动类
package boot.netty.udp; import boot.netty.udp.adapter.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; public class BootNettyUdpServer { /** * 启动服务 */ public void bind(int port) { EventLoopGroup eventLoopGroup = new NioEventLoopGroup(); try { //UDP方式使用Bootstrap Bootstrap serverBootstrap = new Bootstrap(); serverBootstrap = serverBootstrap.group(eventLoopGroup); serverBootstrap = serverBootstrap.channel(NioDatagramChannel.class); serverBootstrap = serverBootstrap.option(ChannelOption.SO_BROADCAST, true); //不需要太多其他的东西,直接这样就可以用 serverBootstrap = serverBootstrap.handler(new BootNettyUdpSimpleChannelInboundHandler()); System.out.println("netty udp start!"); ChannelFuture f = serverBootstrap.bind(port).sync(); f.channel().closeFuture().sync(); } catch (Exception e) { // TODO: handle exception } finally { System.out.println("netty udp close!"); eventLoopGroup.shutdownGracefully(); } } }
4、服务端I/O数据读写处理类
package boot.netty.udp.adapter; 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; 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); //打印收到的消息 System.out.println("msg---"+strdata); //收到udp消息后,可通过此方式原路返回的方式返回消息,例如返回时间戳 ctx.writeAndFlush(new DatagramPacket(Unpooled.copiedBuffer(System.currentTimeMillis()/1000+"", CharsetUtil.UTF_8), msg.sender())); } catch (Exception e) { } } }
可以使用一些UDP客户端的软件来测试,这个Demo应用是基于Netty4.x的,对于Netty5.0有一些小的变化,在I/O数据处理类这里的变化需要注意,channelRead0(ChannelHandlerContext, I)方法改成了messageReceived(ChannelHandlerContext, I)},否则代码会报错然后找不到原因,Netty方法源码上是有注释信息的。