经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Spring » 查看文章
Springboot中用 Netty 开启UDP服务方式
来源:jb51  时间:2021/11/16 13:13:12  对本文有异议

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

  1. <!--springboot version 我用的是2.1.3.RELEASE-->
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter</artifactId>
  5. <version>2.1.3.RELEASE</version>
  6. </dependency>
  7. <!--web模块的启动器 -->
  8. <dependency>
  9. <groupId>org.springframework.boot</groupId>
  10. <artifactId>spring-boot-starter-web</artifactId>
  11. </dependency>
  12. <!-- netty依赖 springboot2.x自动导入版本 -->
  13. <dependency>
  14. <groupId>io.netty</groupId>
  15. <artifactId>netty-all</artifactId>
  16. </dependency>
  17. <!-- 这里我用到了@slf4j 所以引入这个jar -->
  18. <dependency>
  19. <groupId>org.projectlombok</groupId>
  20. <artifactId>lombok</artifactId>
  21. <optional>true</optional>
  22. </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 初始化。

  1. package com.demo.udpdemo.UDPServer;
  2. import com.demo.udpdemo.handler.BootNettyUdpSimpleChannelInboundHandler;
  3. import io.netty.bootstrap.Bootstrap;
  4. import io.netty.channel.ChannelFuture;
  5. import io.netty.channel.ChannelOption;
  6. import io.netty.channel.EventLoopGroup;
  7. import io.netty.channel.nio.NioEventLoopGroup;
  8. import io.netty.channel.socket.nio.NioDatagramChannel;
  9. import lombok.extern.slf4j.Slf4j;
  10. /**
  11. * @author
  12. */
  13. @Slf4j
  14. public class BootNettyUdpServer {
  15. /**
  16. * 启动服务
  17. */
  18. public void bind(int port) {
  19. log.info("-------------------------------udpServer-------------------------");
  20. //表示服务器连接监听线程组,专门接受 accept 新的客户端client 连接
  21. EventLoopGroup bossLoopGroup = new NioEventLoopGroup();
  22. try {
  23. //1,创建netty bootstrap 启动类
  24. Bootstrap serverBootstrap = new Bootstrap();
  25. //2、设置boostrap 的eventLoopGroup线程组
  26. serverBootstrap = serverBootstrap.group(bossLoopGroup);
  27. //3、设置NIO UDP连接通道
  28. serverBootstrap = serverBootstrap.channel(NioDatagramChannel.class);
  29. //4、设置通道参数 SO_BROADCAST广播形式
  30. serverBootstrap = serverBootstrap.option(ChannelOption.SO_BROADCAST, true);
  31. //5、设置处理类 装配流水线
  32. serverBootstrap = serverBootstrap.handler(new BootNettyUdpSimpleChannelInboundHandler());
  33. //6、绑定server,通过调用sync()方法异步阻塞,直到绑定成功
  34. ChannelFuture f = serverBootstrap.bind(port).sync();
  35. log.info(BootNettyUdpServer.class.getName()+" started and listend on "+f.channel().localAddress());
  36. //7、监听通道关闭事件,应用程序会一直等待,直到channel关闭
  37. f.channel().closeFuture().sync();
  38. } catch (Exception e) {
  39. // TODO: handle exception
  40. } finally {
  41. System.out.println("netty udp close!");
  42. //8 关闭EventLoopGroup,
  43. bossLoopGroup.shutdownGracefully();
  44. }
  45. }
  46. }

NettyUdpSimpleChannelInboundHandler

  1. package com.demo.udpdemo.handler;
  2. import io.netty.buffer.Unpooled;
  3. import io.netty.channel.ChannelHandlerContext;
  4. import io.netty.channel.SimpleChannelInboundHandler;
  5. import io.netty.channel.socket.DatagramPacket;
  6. import io.netty.util.CharsetUtil;
  7. import lombok.extern.slf4j.Slf4j;
  8. /**
  9. * @author
  10. */
  11. @Slf4j
  12. public class BootNettyUdpSimpleChannelInboundHandler extends SimpleChannelInboundHandler<DatagramPacket> {
  13. @Override
  14. protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception {
  15. try {
  16. String strdata = msg.content().toString(CharsetUtil.UTF_8);
  17. //打印收到的消息
  18. log.info("---------------------receive data--------------------------");
  19. log.info(strdata);
  20. log.info("---------------------receive data--------------------------");
  21. //收到udp消息后,可通过此方式原路返回的方式返回消息,例如返回时间戳
  22. ctx.writeAndFlush(new DatagramPacket(Unpooled.copiedBuffer("ok", CharsetUtil.UTF_8), msg.sender()));
  23. } catch (Exception e) {
  24. }
  25. }
  26. }

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

  1. @SpringBootApplication
  2. @EnableAsync
  3. public class UdpDemoApplication implements CommandLineRunner {
  4. public static void main(String[] args) {
  5. SpringApplication app = new SpringApplication(UdpDemoApplication.class);
  6. app.run(args);
  7. }
  8. @Async
  9. @Override
  10. public void run(String... args){
  11. new BootNettyUdpServer().bind(51000);
  12. }
  13. }

test

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

sendUdpRequestTest

  1. //定义客户端ip
  2. private static final String SERVER_HOSTNAME = "127.0.0.1";
  3. // 服务器端口
  4. private static final int SERVER_PORT = 51000;
  5. // 本地发送端口
  6. private static final int LOCAL_PORT = 8888;
  7. @Test
  8. public void sendUdpRequestTest() {
  9. try {
  10. // 1,创建udp服务。通过DatagramSocket对象。
  11. DatagramSocket socket = new DatagramSocket(LOCAL_PORT);
  12. // 2,确定数据,并封装成数据包。DatagramPacket(byte[] buf, int length, InetAddress
  13. // address, int port)
  14. byte[] buf = "hello".getBytes();
  15. DatagramPacket dp = new DatagramPacket(buf, buf.length, InetAddress.getByName(SERVER_HOSTNAME),
  16. SERVER_PORT);
  17. // 3,通过socket服务,将已有的数据包发送出去。通过send方法。
  18. socket.send(dp);
  19. // 4,关闭资源。
  20. socket.close();
  21. } catch (IOException e) {
  22. e.printStackTrace();
  23. }
  24. }

结果

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--------------------------

以上为个人经验,希望能给大家一个参考,也希望大家多多支持w3xue。

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号