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)寫一個(gè)簡(jiǎn)單的udp demo。大體思路:
- 寫一個(gè)netty的 基于UDP的Server 用來(lái)接受數(shù)據(jù)
- 寫個(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)線程組,專門接受 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-03
JSP頁(yè)面?zhèn)鲄⒊霈F(xiàn)中文亂碼的解決方案
這篇文章主要介紹了JSP頁(yè)面?zhèn)鲄⒊霈F(xiàn)中文亂碼的解決方案,非常實(shí)用,需要的朋友可以參考下2014-08-08
java中獲取類加載路徑和項(xiàng)目根路徑的5種方式分析
本篇文章介紹了,java中獲取類加載路徑和項(xiàng)目根路徑的5種方式分析。需要的朋友參考下2013-05-05
Java實(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-08
SpringBoot整合Kaptcha實(shí)現(xiàn)圖形驗(yàn)證碼功能
這篇文章主要介紹了SpringBoot整合Kaptcha實(shí)現(xiàn)圖形驗(yàn)證碼功能,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-09-09

