【Netty】UDP协议使用学习

2022-05-01 14:05:43 浏览数 (1)

UDP

传输层协议 :User Datagram Protocal

基于报文传输

分类

TCP

UDP

面向连接

无连接

只有两端 只能一对一通信

可以一对一,一对多,多对一,多对多通信

基于字节流

基于报文

重要特性

可靠

不可爱(尽最大可能交付)

首部占用空间大 20-60字节之间

首部空间小,8字节(记录报文长度)

UDP的分类

  • 单播: 一对一
  • 组播:一对多(组播)
  • 广播 : 多对多(局域网内的全部)

TCP协议已经尽可能的支持了并发 所以大部分还是使用的TCP协议 除非网络很差的情况下使用UDP

原生的UDP实现

  1. DatagramSocket 代表通信的一段
  2. DatagramPacket 是数据的通信格式 报文,
    1. 在创建的时候 需要明确数据是字节数组 以及另一端的ip地址 端口
    2. 在接受报文和发送报文前 使用字节数组进行接收和组装
  3. socket 去接受和发送时,对应receive()和 send() 方法

服务端

代码语言:javascript复制
public class udpServer {
    public static void main(String[] args) throws Exception {

        //DatagramSocket - 用来建立连接,通信的一端
        DatagramSocket socket = new DatagramSocket(6789);
        //DatagramPacket - 报文
        DatagramPacket packet = new DatagramPacket(new byte[1024], 1024);
        while (true) {
            socket.receive(packet);
            byte[] msg = Arrays.copyOfRange(packet.getData(), packet.getOffset(), packet.getOffset()   packet.getLength());
            System.out.println("Receive data"   new String(msg));
            System.out.println("Receive data Form"   packet.getAddress().getHostAddress());
            socket.send(packet);
        }
    }
}

客户端

代码语言:javascript复制
//单播的通信方式
public class udpClient {
    public static void main(String[] args) throws Exception {
        //如果使用多播 使用  MulticastSocket
        DatagramSocket socket = new DatagramSocket();
        InetAddress localHost = InetAddress.getLocalHost();
        SocketAddress socketAddress = new InetSocketAddress(localHost, 6789);
        byte[] msg = new String("hello udp server").getBytes();
        DatagramPacket packet = new DatagramPacket(msg, msg.length, socketAddress);
        socket.send(packet);
        socket.close();
    }
}

Netty的UDP实现

  1. DatagramSocket 对应 NioDatagramChannel
  2. java.net.datagramPacket 对应 import io.netty.channel.socket.DatagramPacket
  3. 无论客户端还是服务端都使用 bootstrap来启动
  4. 通过调用Bootstrap的localAddress()指定端口号,也可以调用remoeteAddress指定连接地址(ip 端口号)
  5. 自定义 handler 的使用 ,继承SimpleChannelInboundHandler 泛型声明为datagramPacket 实现channelread0方法来实现逻辑
  6. 组装datagramPacket 通过byteBuf 加上socketAddress()
  7. 组装bytebuf 调用Unplooled工具类 copiedbuffer方法 明确字符串和编码格式

服务端

代码语言:javascript复制
public class udpNettyServer {
    public static void main(String[] args) {
        EventLoopGroup group = new NioEventLoopGroup();
        //可以统一使用bootstrap进行配置
        Bootstrap bootstrap = new Bootstrap();
        //实现udp协议 使用的通道
        bootstrap.group(group).channel(NioDatagramChannel.class)
                .localAddress(6789)
                .handler(new UdpServerHandler());
        try {
            ChannelFuture future = bootstrap.bind(6789).sync();
            future.channel().closeFuture().await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            group.shutdownGracefully();
        }
    }
}

//DatagramPacket 使用的是netty包下的
class UdpServerHandler extends SimpleChannelInboundHandler<DatagramPacket> {

    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, DatagramPacket datagramPacket) throws Exception {
        System.out.println("receive packet"   datagramPacket.content().toString());
        ByteBuf buf = Unpooled.copiedBuffer("Sth", CharsetUtil.UTF_8);
        //通过组装bytebuf 获取发送报文的发送者 得到要返回的报文
        DatagramPacket packet = new DatagramPacket(buf, datagramPacket.sender());
        channelHandlerContext.writeAndFlush(packet);
    }
}

客户端

代码语言:javascript复制
public class udpNettyClient {
    public static void main(String[] args) {
        EventLoopGroup group = new NioEventLoopGroup();
        //可以统一使用bootstrap进行配置
        Bootstrap bootstrap = new Bootstrap();
        //实现udp协议 使用的通道
        bootstrap.group(group).channel(NioDatagramChannel.class)
                .remoteAddress("127.0.0.1", 6789)
                .handler(new udpClientHandler());
        try {
            Channel channel = bootstrap.bind(0).sync().channel();
            ByteBuf buf = Unpooled.copiedBuffer("Send sth", CharsetUtil.UTF_8);
            //通过组装bytebuf 获取发送报文的发送者 得到要返回的报文
            DatagramPacket packet = new DatagramPacket(buf, SocketUtils.socketAddress("127.0.0.1", 6789));
            channel.writeAndFlush(packet).sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            group.shutdownGracefully();
        }
    }
}

class udpClientHandler extends SimpleChannelInboundHandler<DatagramPacket> {

    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, DatagramPacket datagramPacket) throws Exception {
        String resp = datagramPacket.content().toString(CharsetUtil.UTF_8);
        System.out.println(resp);
        channelHandlerContext.close();
    }
}

0 人点赞