Springboot中用 Netty 開(kāi)啟UDP服務(wù)方式
Netty
Netty是一種提供網(wǎng)絡(luò)編程的工具,是對(duì)socket編程的一例優(yōu)秀的包裝,支持TCP、UDP、FTP等協(xié)議。我們可以用Netty開(kāi)發(fā)自己的http服務(wù)器、udp服務(wù)器、FTP服務(wù)器,RPC服務(wù)器等
Netty大受歡迎的原因:
- 并發(fā)高
Netty支持NIO編程,NIO的持支,可以大大提升并發(fā)性能。
- 傳輸快
Netty NIO的一個(gè)特性是零拷貝,直接在內(nèi)存中開(kāi)辟一塊,剩去了socket緩沖區(qū),
- 封裝好
接下來(lái)寫(xiě)一個(gè)簡(jiǎn)單的udp demo。大體思路:
- 寫(xiě)一個(gè)netty的 基于UDP的Server 用來(lái)接受數(shù)據(jù)
- 寫(xiě)個(gè)一處理類,用于對(duì)接受的數(shù)據(jù)進(jìn)行處理,然后返回信息
新建一個(gè)springboot項(xiàng)目。在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模塊的啟動(dòng)器 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- netty依賴 springboot2.x自動(dòng)導(dǎo)入版本 --> <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> </dependency> <!-- 這里我用到了@slf4j 所以引入這個(gè)jar --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency>
創(chuàng)建NettyUDPServer
Channel 通道的類型
NioSocketChannel
, 代表異步的客戶端 TCP Socket 連接.NioServerSocketChannel
, 異步的服務(wù)器端 TCP Socket 連接.NioDatagramChannel
, 異步的 UDP 連接NioSctpChannel
, 異步的客戶端 Sctp 連接.NioSctpServerChannel
, 異步的 Sctp 服務(wù)器端連接.OioSocketChannel
, 同步的客戶端 TCP Socket 連接.OioServerSocketChannel
, 同步的服務(wù)器端 TCP Socket 連接.OioDatagramChannel
, 同步的 UDP 連接OioSctpChannel
, 同步的 Sctp 服務(wù)器端連接.OioSctpServerChannel
, 同步的客戶端 TCP Socket 連接.
Bootstrap 是 Netty 提供的一個(gè)便利的工廠類,可以通過(guò)它來(lái)完成 Netty 的客戶端或服務(wù)器端的 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 { /** * 啟動(dòng)服務(wù) */ public void bind(int port) { log.info("-------------------------------udpServer-------------------------"); //表示服務(wù)器連接監(jiān)聽(tīng)線程組,專門(mén)接受 accept 新的客戶端client 連接 EventLoopGroup bossLoopGroup = new NioEventLoopGroup(); try { //1,創(chuàng)建netty bootstrap 啟動(dòng)類 Bootstrap serverBootstrap = new Bootstrap(); //2、設(shè)置boostrap 的eventLoopGroup線程組 serverBootstrap = serverBootstrap.group(bossLoopGroup); //3、設(shè)置NIO UDP連接通道 serverBootstrap = serverBootstrap.channel(NioDatagramChannel.class); //4、設(shè)置通道參數(shù) SO_BROADCAST廣播形式 serverBootstrap = serverBootstrap.option(ChannelOption.SO_BROADCAST, true); //5、設(shè)置處理類 裝配流水線 serverBootstrap = serverBootstrap.handler(new BootNettyUdpSimpleChannelInboundHandler()); //6、綁定server,通過(guò)調(diào)用sync()方法異步阻塞,直到綁定成功 ChannelFuture f = serverBootstrap.bind(port).sync(); log.info(BootNettyUdpServer.class.getName()+" started and listend on "+f.channel().localAddress()); //7、監(jiān)聽(tīng)通道關(guān)閉事件,應(yīng)用程序會(huì)一直等待,直到channel關(guān)閉 f.channel().closeFuture().sync(); } catch (Exception e) { // TODO: handle exception } finally { System.out.println("netty udp close!"); //8 關(guān)閉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消息后,可通過(guò)此方式原路返回的方式返回消息,例如返回時(shí)間戳 ctx.writeAndFlush(new DatagramPacket(Unpooled.copiedBuffer("ok", CharsetUtil.UTF_8), msg.sender())); } catch (Exception e) { } } }
修改啟動(dòng)類,啟動(dòng)執(zhí)行UDPServer.bind方法,啟動(dòng)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類下面,新建一個(gè)test方法
sendUdpRequestTest
//定義客戶端ip private static final String SERVER_HOSTNAME = "127.0.0.1"; // 服務(wù)器端口 private static final int SERVER_PORT = 51000; // 本地發(fā)送端口 private static final int LOCAL_PORT = 8888; @Test public void sendUdpRequestTest() { try { // 1,創(chuàng)建udp服務(wù)。通過(guò)DatagramSocket對(duì)象。 DatagramSocket socket = new DatagramSocket(LOCAL_PORT); // 2,確定數(shù)據(jù),并封裝成數(shù)據(jù)包。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,通過(guò)socket服務(wù),將已有的數(shù)據(jù)包發(fā)送出去。通過(guò)send方法。 socket.send(dp); // 4,關(guān)閉資源。 socket.close(); } catch (IOException e) { e.printStackTrace(); } }
結(jié)果
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--------------------------
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
java ssm框架實(shí)現(xiàn)分頁(yè)功能的示例代碼(oracle)
這篇文章主要介紹了java ssm框架實(shí)現(xiàn)分頁(yè)功能的示例代碼(oracle),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-03-03JSP頁(yè)面?zhèn)鲄⒊霈F(xiàn)中文亂碼的解決方案
這篇文章主要介紹了JSP頁(yè)面?zhèn)鲄⒊霈F(xiàn)中文亂碼的解決方案,非常實(shí)用,需要的朋友可以參考下2014-08-08java中獲取類加載路徑和項(xiàng)目根路徑的5種方式分析
本篇文章介紹了,java中獲取類加載路徑和項(xiàng)目根路徑的5種方式分析。需要的朋友參考下2013-05-05Java實(shí)現(xiàn)基于token認(rèn)證的方法示例
這篇文章主要介紹了Java實(shí)現(xiàn)基于token認(rèn)證的方法示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08SpringBoot整合Kaptcha實(shí)現(xiàn)圖形驗(yàn)證碼功能
這篇文章主要介紹了SpringBoot整合Kaptcha實(shí)現(xiàn)圖形驗(yàn)證碼功能,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-09-09