Java NIO UDP DEMO


 今天有人問我Netty的UDP怎么使用,我自己嘗試的去寫一個Demo,在網上搜索了一下,關於Netty的UDP實現還是很少的,所以,今天寫下這篇文章用來記錄今天的一個簡單Demo實現

 

不使用Netty的UDP實例:

UdpServer.java

package com.rainy.netty.udp02;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

/**
 * Created by smzdm on 16/8/10.
 */
public class UdpServer {

    public static final int PORT = 30000;
    // 定義每個數據報的最大大小為4KB
    private static final int DATA_LEN = 4096;
    // 定義接收網絡數據的字節數組
    byte[] inBuff = new byte[DATA_LEN];
    // 以指定字節數組創建准備接收數據的DatagramPacket對象
    private DatagramPacket inPacket =
            new DatagramPacket(inBuff, inBuff.length);
    // 定義一個用於發送的DatagramPacket對象
    private DatagramPacket outPacket;
    // 定義一個字符串數組,服務器端發送該數組的元素
    String[] books = new String[] {
                    "瘋狂Java講義",
                    "輕量級Java EE企業應用實戰",
                    "瘋狂Android講義",
                    "瘋狂Ajax講義"
            };

    public void init() throws IOException {
        try {
            // 創建DatagramSocket對象
            DatagramSocket socket = new DatagramSocket(PORT);
            // 采用循環接收數據
            for (int i = 0; i < 1000; i++) {
                // 讀取Socket中的數據,讀到的數據放入inPacket封裝的數組里
                socket.receive(inPacket);
                // 判斷inPacket.getData()和inBuff是否是同一個數組
                System.out.println(inBuff == inPacket.getData());
                // 將接收到的內容轉換成字符串后輸出
                System.out.println(new String(inBuff
                        , 0, inPacket.getLength()));
                // 從字符串數組中取出一個元素作為發送數據
                byte[] sendData = books[i % 4].getBytes();
                // 以指定的字節數組作為發送數據,以剛接收到的DatagramPacket的
                // 源SocketAddress作為目標SocketAddress創建DatagramPacket
                outPacket = new DatagramPacket(sendData
                        , sendData.length, inPacket.getSocketAddress());
                // 發送數據
                socket.send(outPacket);
            }
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

    public static void main(String[] args) throws IOException {
        new UdpServer().init();
    }
}

 

UdpClient.java

package com.rainy.netty.udp02;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;

/**
 * Created by smzdm on 16/8/10.
 */
public class UdpClient {

    // 定義發送數據報的目的地
    public static final int DEST_PORT = 30000;
    public static final String DEST_IP = "127.0.0.1";
    // 定義每個數據報的最大大小為4KB
    private static final int DATA_LEN = 4096;
    // 定義接收網絡數據的字節數組
    byte[] inBuff = new byte[DATA_LEN];
    // 以指定的字節數組創建准備接收數據的DatagramPacket對象
    private DatagramPacket inPacket =
            new DatagramPacket(inBuff, inBuff.length);
    // 定義一個用於發送的DatagramPacket對象
    private DatagramPacket outPacket = null;

    public void init() throws IOException {
        try {
            // 創建一個客戶端DatagramSocket,使用隨機端口
            DatagramSocket socket = new DatagramSocket();
            // 初始化發送用的DatagramSocket,它包含一個長度為0的字節數組
            outPacket = new DatagramPacket(new byte[0], 0
                    , InetAddress.getByName(DEST_IP), DEST_PORT);
            // 創建鍵盤輸入流
            Scanner scan = new Scanner(System.in);
            // 不斷地讀取鍵盤輸入
            while (scan.hasNextLine()) {
                // 將鍵盤輸入的一行字符串轉換成字節數組
                byte[] buff = scan.nextLine().getBytes();
                // 設置發送用的DatagramPacket中的字節數據
                outPacket.setData(buff);
                // 發送數據報
                socket.send(outPacket);
                // 讀取Socket中的數據,讀到的數據放在inPacket所封裝的字節數組中
                socket.receive(inPacket);
                System.out.println(new String(inBuff, 0 , inPacket.getLength()));
            }
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

    public static void main(String[] args) throws IOException {
        new UdpClient().init();
    }

}

這兩段代碼是在網上搜羅的例子,

原文路徑:http://blog.csdn.net/jiangxinyu/article/details/8161044

 

      在這個例子中,我們可以看到,UDP的實現方式和TCP的實現方式上是不同的,UDP的實現在於,發送數據包,后面我也在網上查看了一些問題,關於粘包問題,我發現,網上部分說UDP有粘包問題,部分說沒有UDP粘包問題,就算有也是很少量的不容易出現的問題,其實,我偏向於UDP沒有粘包問題,因為UDP本身是按包發送,而且,UDP和TCP不一樣,UDP是包完整就發送,而TCP在包完整的情況下,會判斷是否值得發送,有發送緩存的實現,所以,綜合分析,我覺得UDP應該是不存在粘包問題,拆包問題同樣就沒有了。

 

Netty實現UDP的案例,

NettyUdpServer.java

package com.rainy.netty.udp01;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.socket.nio.NioDatagramChannel;

/**
* Created by smzdm on 16/8/10.
*/
public class NettyUdpServer {

public static void main(String[] args) throws InterruptedException {
Bootstrap b = new Bootstrap();
EventLoopGroup group = new NioEventLoopGroup();
b.group(group)
.channel(NioDatagramChannel.class)
.option(ChannelOption.SO_BROADCAST, true)
.handler(new UDPSeverHandler());

b.bind(9000).sync().channel().closeFuture().await();
}

}

class UDPSeverHandler extends SimpleChannelInboundHandler<DatagramPacket> {

@Override
protected void messageReceived(ChannelHandlerContext ctx, DatagramPacket packet) throws Exception {
ByteBuf buf = (ByteBuf) packet.copy().content();
byte[] req = new byte[buf.readableBytes()];
buf.readBytes(req);
String body = new String(req, "UTF-8");
System.out.println(body);
}

@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
super.channelRegistered(ctx);
System.out.println("I got it!");
}

}

 

NettyUdpClient.java

package com.rainy.netty.udp;

import java.net.InetSocketAddress;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.util.CharsetUtil;

/**
 * Created by smzdm on 16/8/10.
 */
public class NettyUdpClient {

    public static void main(String[] args) {
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap b = new Bootstrap();
            b.group(group).channel(NioDatagramChannel.class)
                    .option(ChannelOption.SO_BROADCAST,true)
                    .handler(new UdpClientHandler());

            Channel ch = b.bind(0).sync().channel();
            // 向網段類所有機器廣播發UDP
            ch.writeAndFlush(
                    new DatagramPacket(
                            Unpooled.copiedBuffer("發送第一個UDP", CharsetUtil.UTF_8),
                            new InetSocketAddress("127.0.0.1", 9000))).sync();
            if(!ch.closeFuture().await(15000)){
                System.out.println("查詢超時!!!");
            }
        } catch (Exception e) {
            System.out.println(e.getMessage());
        } finally {
            group.shutdownGracefully();
        }
    }
}

class UdpClientHandler extends SimpleChannelInboundHandler<DatagramPacket> {
    @Override
    public void messageReceived(ChannelHandlerContext channelHandlerContext,
            DatagramPacket datagramPacket) throws Exception {

        String response = datagramPacket.content().toString(CharsetUtil.UTF_8);
        if(response.startsWith("結果:")){
            System.out.println(response);
            channelHandlerContext.close();
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx,Throwable cause)throws Exception{
        ctx.close();
        cause.printStackTrace();
    }
}

 

netty對應原文路徑:http://www.tuicool.com/articles/Rry6biF

上面的例子作為參考進行的代碼處理,發現這樣就能使得代碼正常發送,如果你需要獲取對應的發送端的IP地址,那么,你可以使用

    packet.sender().getAddress().getHostAddress();
進行獲取發送端IP地址,本質上來說,這個UDP一般都是基於使用UDP的方式進行自定義協議方式實現業務功能,具體可以根據自己的文檔格式進行對應的解析。這個方式,如果做過銀行接口的,應該對這個接口實現方式有一定的認識。

本文暫時先寫到這里,如果有什么問題,請留言。大家一起交流討論NIO方面的問題,一起進步。

 


免責聲明!

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



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