zoukankan      html  css  js  c++  java
  • 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方面的问题,一起进步。

  • 相关阅读:
    Django之模板系统
    Django之ORM操作
    Django之路由分配系统
    基于模态对话框 学生管理系统
    初识Django
    ORM框架之SQLALchemy
    MySQL查询性能调优化
    MySQL练习题
    MySQL自带功能介绍
    javascript时间戳和日期字符串相互转换
  • 原文地址:https://www.cnblogs.com/rainy-shurun/p/5756501.html
Copyright © 2011-2022 走看看