Netty4.x中文教程系列(七)UDP協議


         

  將近快一年時間沒有更新Netty的博客。一方面原因是因為項目進度的問題。另外一方面是博主有一段時間去熟悉Unity3D引擎。

  本章節主要記錄博主自己Netty的UDP協議使用。

  1.  構建UDP服務端

  首先我們應該清楚UDP協議是一種無連接狀態的協議。所以Netty框架區別於一般的有鏈接協議服務端啟動程序(ServerBootstrap)。

  Netty開發基於UDP協議的服務端需要使用Bootstrap

  

 1 package dev.tinyz.game;
 2 
 3 import io.netty.bootstrap.Bootstrap;
 4 import io.netty.buffer.Unpooled;
 5 import io.netty.channel.*;
 6 import io.netty.channel.nio.NioEventLoopGroup;
 7 import io.netty.channel.socket.DatagramPacket;
 8 import io.netty.channel.socket.nio.NioDatagramChannel;
 9 import io.netty.handler.codec.MessageToMessageDecoder;
10 
11 import java.net.InetSocketAddress;
12 import java.nio.charset.Charset;
13 import java.util.List;
14 
15 /**
16  * @author TinyZ on 2015/6/8.
17  */
18 public class GameMain {
19 
20     public static void main(String[] args) throws InterruptedException {
21 
22         final NioEventLoopGroup nioEventLoopGroup = new NioEventLoopGroup();
23 
24         Bootstrap bootstrap = new Bootstrap();
25         bootstrap.channel(NioDatagramChannel.class);
26         bootstrap.group(nioEventLoopGroup);
27         bootstrap.handler(new ChannelInitializer<NioDatagramChannel>() {
28 
29             @Override
30             public void channelActive(ChannelHandlerContext ctx) throws Exception {
31                 super.channelActive(ctx);
32             }
33 
34             @Override
35             protected void initChannel(NioDatagramChannel ch) throws Exception {
36                 ChannelPipeline cp = ch.pipeline();
37                 cp.addLast("framer", new MessageToMessageDecoder<DatagramPacket>() {
38                     @Override
39                     protected void decode(ChannelHandlerContext ctx, DatagramPacket msg, List<Object> out) throws Exception {
40                         out.add(msg.content().toString(Charset.forName("UTF-8")));
41                     }
42                 }).addLast("handler", new UdpHandler());
43             }
44         });
45         // 監聽端口
46         ChannelFuture sync = bootstrap.bind(9009).sync();
47         Channel udpChannel = sync.channel();
48 
49 //        String data = "我是大好人啊";
50 //        udpChannel.writeAndFlush(new DatagramPacket(Unpooled.copiedBuffer(data.getBytes(Charset.forName("UTF-8"))), new InetSocketAddress("192.168.2.29", 9008)));
51 
52         Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
53             @Override
54             public void run() {
55                 nioEventLoopGroup.shutdownGracefully();
56             }
57         }));
58     }
59 }
View Code

  於Tcp協議的客戶端啟動程序基本一樣。唯一區別就在於,UDP服務器使用的是bind方法,來監聽端口

  在Netty的Bootstrap類中的注釋,發現有如下注釋內容:

  

  大意就是:bind()用於UDP, TCP連接使用connect()。

  上面的源碼監聽的是端口9009,那么所有使用UDP協議的數據,發送到端口9009,就會被我們的Netty接收到了。

  為了輸出方便,博主在上面的代碼中增加一個MessageToMessageDecoder將接收到的Datagram,排除其他信息,僅將字符串傳遞下去。並在UDPHandler中打印出來。

  2.  構建UDP客戶端

  UDP協議來說,其實沒有客戶端和服務端的區別啦。只是為了貼近TCP協議做的一點文字描述上面的區分。

  簡單來講,上面的那段邏輯其實就可以作為UDP客戶端來使用。注釋掉的那行邏輯其實就是發送“我是大好人啊”這個字符串到ip地址為192.168.2.29的服務端的9008端口。代碼如下:

  

 1 package dev.tinyz.game;
 2 
 3 import io.netty.bootstrap.Bootstrap;
 4 import io.netty.buffer.Unpooled;
 5 import io.netty.channel.*;
 6 import io.netty.channel.nio.NioEventLoopGroup;
 7 import io.netty.channel.socket.DatagramPacket;
 8 import io.netty.channel.socket.nio.NioDatagramChannel;
 9 import io.netty.handler.codec.MessageToMessageDecoder;
10 
11 import java.net.InetSocketAddress;
12 import java.nio.charset.Charset;
13 import java.util.List;
14 
15 /**
16  * @author TinyZ on 2015/6/8.
17  */
18 public class GameMain {
19 
20     public static void main(String[] args) throws InterruptedException {
21 
22         final NioEventLoopGroup nioEventLoopGroup = new NioEventLoopGroup();
23 
24         Bootstrap bootstrap = new Bootstrap();
25         bootstrap.channel(NioDatagramChannel.class);
26         bootstrap.group(nioEventLoopGroup);
27         bootstrap.handler(new ChannelInitializer<NioDatagramChannel>() {
28 
29             @Override
30             public void channelActive(ChannelHandlerContext ctx) throws Exception {
31                 super.channelActive(ctx);
32             }
33 
34             @Override
35             protected void initChannel(NioDatagramChannel ch) throws Exception {
36                 ChannelPipeline cp = ch.pipeline();
37                 cp.addLast("framer", new MessageToMessageDecoder<DatagramPacket>() {
38                     @Override
39                     protected void decode(ChannelHandlerContext ctx, DatagramPacket msg, List<Object> out) throws Exception {
40                         out.add(msg.content().toString(Charset.forName("UTF-8")));
41                     }
42                 }).addLast("handler", new UdpHandler());
43             }
44         });
45         // 監聽端口
46         ChannelFuture sync = bootstrap.bind(0).sync();
47         Channel udpChannel = sync.channel();
48 
49         String data = "我是大好人啊";
50         udpChannel.writeAndFlush(new DatagramPacket(Unpooled.copiedBuffer(data.getBytes(Charset.forName("UTF-8"))), new InetSocketAddress("192.168.2.29", 9008)));
51 
52         Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
53             @Override
54             public void run() {
55                 nioEventLoopGroup.shutdownGracefully();
56             }
57         }));
58     }
59 }
View Code

  和上面的“服務端”代碼最大的差別就是,監聽的端口號修改成0.

  使用Netty的Channel發送DatagramPacket。寫好目標地址,然后運行起來就可以自己測試一下了。

  3.  JAVA原生UDP

  有朋友這個時候就會問:為什么不是有JAVA原生的UDP呢?

  其實很簡單。說白了Netty使用的也是Java底層的代碼。只是做了一層封裝,以便於使用。服務端使用Netty框架構建高性能,高擴展的UDP服務器。

  客戶端則使用JAVA或者任意其他的語言的API(遵循UDP協議即可)。

  下面上一段博主使用的的JAVA

  

 1 package dev.tinyz.game;
 2 
 3 import java.io.IOException;
 4 import java.net.DatagramPacket;
 5 import java.net.DatagramSocket;
 6 import java.net.InetSocketAddress;
 7 import java.nio.charset.Charset;
 8 
 9 /**
10  * @author TinyZ on 2015/6/10.
11  */
12 public class UdpTest {
13 
14     public static void main(String[] args) throws IOException {
15         final String data = "博主郵箱:zou90512@126.com";
16         byte[] bytes = data.getBytes(Charset.forName("UTF-8"));
17         InetSocketAddress targetHost = new InetSocketAddress("192.168.2.29", 9009);
18 
19         // 發送udp內容
20         DatagramSocket socket = new DatagramSocket();
21         socket.send(new DatagramPacket(bytes, 0, bytes.length, targetHost));
22     }
23 }
View Code

  ..

  ps.UDP協議最大特點就是效率高,速度快。用於某些場合可以極大改善系統的性能。

  博主在這里引入這個Netty實現UDP的服務端,主要目的。嘻嘻。就是想開源拙作:eyeOfSauron日志系統。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM