小傅哥 | https://bugstack.cn
沉澱、分享、成長,讓自己和他人都能有所收獲。專注于原創專題案例編寫,目前已完成的專題有;Netty4.x實戰專題案例、用Java實作JVM、基于JavaAgent的全鍊路監控、手寫RPC架構、架構設計專題案例、源碼分析等。你用劍🗡、我用刀🔪,好的代碼都很燒,望你不吝出招!
一、前言介紹
在Netty通信中UDP的實作方式也非常簡單,隻要注意部分代碼差別于TCP即可。本章節需要注意的知識點 ;NioDatagramChannel、ChannelOption.SO_BROADCAST
Internet 協定集支援一個無連接配接的傳輸協定,該協定稱為使用者資料報協定(UDP,User Datagram Protocol)。UDP 為應用程式提供了一種無需建立連接配接就可以發送封裝的 IP 資料報的方法。RFC 768 1 描述了 UDP。
Internet 的傳輸層有兩個主要協定,互為補充。無連接配接的是 UDP,它除了給應用程式發送資料包功能并允許它們在所需的層次上架構自己的協定之外,幾乎沒有做什麼特别的的事情。面向連接配接的是 TCP,該協定幾乎做了所有的事情。
二、環境準備
1、jdk1.8【jdk1.7以下隻能部分支援netty】
2、Netty4.1.36.Final【netty3.x 4.x 5每次的變化較大,接口類名也随着變化】
3、NetAssist 網絡調試助手,可以從網上下載下傳也可以聯系我,微信公衆号:bugstack蟲洞棧 | 關注回複你的郵箱
三、代碼示例
itstack-demo-netty-1-11
└── src
├── main
│ └── java
│ └── org.itstack.demo.netty
│ ├── client
│ │ ├── MyChannelInitializer.java
│ │ ├── MyClientHandler.java
│ │ └── NettyClient.java
│ └── server
│ ├── MyChannelInitializer.java
│ ├── MyServerHandler.java
│ └── NettyServer.java
└── test
└── java
└── org.itstack.demo.netty.test
└── ApiTest.java
複制
client/MyChannelInitializer.java
/**
* 蟲洞棧:https://bugstack.cn
* 公衆号:bugstack蟲洞棧 {擷取學習源碼}
* 蟲洞群:①群5398358 ②群5360692
* Create by fuzhengwei on @2019
*/
public class MyChannelInitializer extends ChannelInitializer<NioDatagramChannel> {
@Override
protected void initChannel(NioDatagramChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
// 解碼轉String,注意調整自己的編碼格式GBK、UTF-8
//pipeline.addLast("stringDecoder", new StringDecoder(Charset.forName("GBK")));
pipeline.addLast(new MyClientHandler());
}
}
複制
client/MyClientHandler.java
/**
* 蟲洞棧:https://bugstack.cn
* 公衆号:bugstack蟲洞棧 {擷取學習源碼}
* 蟲洞群:①群5398358 ②群5360692
* Create by fuzhengwei on @2019
*/
public class MyClientHandler extends SimpleChannelInboundHandler<DatagramPacket> {
//接受服務端發送的内容
@Override
protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) throws Exception {
String msg = packet.content().toString(Charset.forName("GBK"));
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + " UDP用戶端接收到消息:" + msg);
}
}
複制
client/NettyClient.java
/**
* 蟲洞棧:https://bugstack.cn
* 公衆号:bugstack蟲洞棧 {擷取學習源碼}
* 蟲洞群:①群5398358 ②群5360692
* Create by fuzhengwei on @2019
*/
public class NettyClient {
public static void main(String[] args) {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group).channel(NioDatagramChannel.class)
.handler(new MyChannelInitializer());
Channel ch = b.bind(7398).sync().channel();
//向目标端口發送資訊
ch.writeAndFlush(new DatagramPacket(
Unpooled.copiedBuffer("你好端口7397的bugstack蟲洞棧,我是用戶端小愛,你在嗎!", Charset.forName("GBK")),
new InetSocketAddress("127.0.0.1", 7397))).sync();
ch.closeFuture().await();
} catch (Exception e) {
e.printStackTrace();
} finally {
group.shutdownGracefully();
}
}
}
複制
server/MyChannelInitializer.java
/**
* 蟲洞棧:https://bugstack.cn
* 公衆号:bugstack蟲洞棧 {擷取學習源碼}
* 蟲洞群:①群5398358 ②群5360692
* Create by fuzhengwei on @2019
*/
public class MyChannelInitializer extends ChannelInitializer<NioDatagramChannel> {
private EventLoopGroup group = new NioEventLoopGroup();
@Override
protected void initChannel(NioDatagramChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
// 解碼轉String,注意調整自己的編碼格式GBK、UTF-8
//pipeline.addLast("stringDecoder", new StringDecoder(Charset.forName("GBK")));
pipeline.addLast(group, new MyServerHandler());
}
}
複制
server/MyServerHandler.java
/**
* 蟲洞棧:https://bugstack.cn
* 公衆号:bugstack蟲洞棧 {擷取學習源碼}
* 蟲洞群:①群5398358 ②群5360692
* Create by fuzhengwei on @2019
*/
public class MyServerHandler extends SimpleChannelInboundHandler<DatagramPacket> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) throws Exception {
String msg = packet.content().toString(Charset.forName("GBK"));
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + " UDP服務端接收到消息:" + msg);
//向用戶端發送消息
String json = "微信公衆号:bugstack蟲洞棧,通知:我已經收到你的消息\r\n";
// 由于資料報的資料是以字元數組傳的形式存儲的,是以傳轉資料
byte[] bytes = json.getBytes(Charset.forName("GBK"));
DatagramPacket data = new DatagramPacket(Unpooled.copiedBuffer(bytes), packet.sender());
ctx.writeAndFlush(data);//向用戶端發送消息
}
}
複制
server/NettyServer.java
/**
* 蟲洞棧:https://bugstack.cn
* 公衆号:bugstack蟲洞棧 {擷取學習源碼}
* 蟲洞群:①群5398358 ②群5360692
* Create by fuzhengwei on @2019
*/
public class NettyServer {
public static void main(String[] args) throws InterruptedException {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioDatagramChannel.class)
.option(ChannelOption.SO_BROADCAST, true) //廣播
.option(ChannelOption.SO_RCVBUF, 2048 * 1024)// 設定UDP讀緩沖區為2M
.option(ChannelOption.SO_SNDBUF, 1024 * 1024)// 設定UDP寫緩沖區為1M
.handler(new MyChannelInitializer());
ChannelFuture f = b.bind(7397).sync();
System.out.println("itstack-demo-netty udp server start done. {關注公衆号:bugstack蟲洞棧,擷取源碼}");
f.channel().closeFuture().sync();
} finally {
//優雅的關閉釋放記憶體
group.shutdownGracefully();
}
}
}
複制
四、測試結果
啟動NettyServer
itstack-demo-netty udp server start done. {關注公衆号:bugstack蟲洞棧,擷取源碼}
2019-09-01 16:58:34 UDP服務端接收到消息:你好端口7397的bugstack蟲洞棧,我是用戶端小愛,你在嗎!
2019-09-01 16:59:15 UDP服務端接收到消息:你好,有人在關注bugstack公衆号,關注可以獲得源碼!
2019-09-01 16:59:15 UDP服務端接收到消息:你好,有人在關注bugstack公衆号,關注可以獲得源碼!
2019-09-01 16:59:16 UDP服務端接收到消息:你好,有人在關注bugstack公衆号,關注可以獲得源碼!
2019-09-01 16:59:17 UDP服務端接收到消息:你好,有人在關注bugstack公衆号,關注可以獲得源碼!
2019-09-01 16:59:17 UDP服務端接收到消息:你好,有人在關注bugstack公衆号,關注可以獲得源碼!
2019-09-01 16:59:18 UDP服務端接收到消息:你好,有人在關注bugstack公衆号,關注可以獲得源碼!
2019-09-01 16:59:18 UDP服務端接收到消息:你好,有人在關注bugstack公衆号,關注可以獲得源碼!
2019-09-01 16:59:19 UDP服務端接收到消息:你好,有人在關注bugstack公衆号,關注可以獲得源碼!
2019-09-01 16:59:19 UDP服務端接收到消息:你好,有人在關注bugstack公衆号,關注可以獲得源碼!
Process finished with exit code -1
複制
啟動NettyClient
2019-09-01 16:58:34 UDP用戶端接收到消息:微信公衆号:bugstack蟲洞棧,通知:我已經收到你的消息
Process finished with exit code -1
複制
在啟動一個網絡調試助手,NetAssist | 這樣友善我們驗證