Springboot中用 Netty 開啟UDP服務(wù)方式
Netty
Netty是一種提供網(wǎng)絡(luò)編程的工具,是對socket編程的一例優(yōu)秀的包裝,支持TCP、UDP、FTP等協(xié)議。我們可以用Netty開發(fā)自己的http服務(wù)器、udp服務(wù)器、FTP服務(wù)器,RPC服務(wù)器等
Netty大受歡迎的原因:
- 并發(fā)高
Netty支持NIO編程,NIO的持支,可以大大提升并發(fā)性能。
- 傳輸快
Netty NIO的一個特性是零拷貝,直接在內(nèi)存中開辟一塊,剩去了socket緩沖區(qū),
- 封裝好
接下來寫一個簡單的udp demo。大體思路:
- 寫一個netty的 基于UDP的Server 用來接受數(shù)據(jù)
- 寫個一處理類,用于對接受的數(shù)據(jù)進(jìn)行處理,然后返回信息
新建一個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自動導(dǎo)入版本 -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
</dependency>
<!-- 這里我用到了@slf4j 所以引入這個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 提供的一個便利的工廠類,可以通過它來完成 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 {
/**
* 啟動服務(wù)
*/
public void bind(int port) {
log.info("-------------------------------udpServer-------------------------");
//表示服務(wù)器連接監(jiān)聽線程組,專門接受 accept 新的客戶端client 連接
EventLoopGroup bossLoopGroup = new NioEventLoopGroup();
try {
//1,創(chuàng)建netty bootstrap 啟動類
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,通過調(diào)用sync()方法異步阻塞,直到綁定成功
ChannelFuture f = serverBootstrap.bind(port).sync();
log.info(BootNettyUdpServer.class.getName()+" started and listend on "+f.channel().localAddress());
//7、監(jiān)聽通道關(guān)閉事件,應(yīng)用程序會一直等待,直到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消息后,可通過此方式原路返回的方式返回消息,例如返回時間戳
ctx.writeAndFlush(new DatagramPacket(Unpooled.copiedBuffer("ok", CharsetUtil.UTF_8), msg.sender()));
} catch (Exception e) {
}
}
}
修改啟動類,啟動執(zhí)行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";
// 服務(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ù)。通過DatagramSocket對象。
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,通過socket服務(wù),將已有的數(shù)據(jù)包發(fā)送出去。通過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--------------------------
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
java ssm框架實現(xiàn)分頁功能的示例代碼(oracle)
這篇文章主要介紹了java ssm框架實現(xiàn)分頁功能的示例代碼(oracle),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-03-03
JSP頁面?zhèn)鲄⒊霈F(xiàn)中文亂碼的解決方案
這篇文章主要介紹了JSP頁面?zhèn)鲄⒊霈F(xiàn)中文亂碼的解決方案,非常實用,需要的朋友可以參考下2014-08-08
Java實現(xiàn)基于token認(rèn)證的方法示例
這篇文章主要介紹了Java實現(xiàn)基于token認(rèn)證的方法示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08
SpringBoot整合Kaptcha實現(xiàn)圖形驗證碼功能
這篇文章主要介紹了SpringBoot整合Kaptcha實現(xiàn)圖形驗證碼功能,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-09-09

