乐趣区

关于netty:netty系列之使用UDP协议

简介

在之前的系列文章中,咱们到了应用 netty 做聊天服务器,聊天服务器应用的 SocketChannel,也就是说底层的协定应用的是 Scoket。明天咱们将会给大家介绍如何在 netty 中应用 UDP 协定。

UDP 协定

UDP(User Datagram Protocol ),也叫用户数据报协定。

UDP 的次要性能和亮点并不在于它引入了什么个性,而在于它疏忽的那些个性:不保障音讯交付,不保障交付程序,不跟踪连贯状态,不须要拥塞管制。

咱们来看一下 UDP 的数据包:

UDP 是一种无连贯的协定,发送者只管发送数据包即可,并不负责解决和保证数据是否胜利发送,数据是否被解决实现等。它的惟一作用就是发送。

在 JDK 中示意 UDP 的有一个专门的类叫做:java.net.DatagramPacket, 在 NIO 中还有一个 java.nio.channels.DatagramChannel, 专门负责解决 UDP 的 channel。

这里咱们要将的是 netty,netty 中对于 UDP 协定也有下面的两个类,名字尽管是一样的,然而对应的包不同。他们别离是:

io.netty.channel.socket.DatagramPacket 和 io.netty.channel.socket.DatagramChannel,当然 netty 中的这两个类是对 JDK 自带类的加强。

先看一下 netty 中 DatagramPacket 的定义:

public class DatagramPacket
        extends DefaultAddressedEnvelope<ByteBuf, InetSocketAddress> implements ByteBufHolder 

DatagramPacket 类实现了 ByteBufHolder 接口,示意它外面寄存的是 ByteBuf。而后他又继承自 DefaultAddressedEnvelope,这个类是对地址的封装,其中 ByteBuf 示意传递音讯的类型,InetSocketAddress 示意指标的地址,它是一个 IP 地址 + 端口号的封装。

从下面的 UDP 协定咱们晓得,UDP 只须要晓得指标地址和对应的音讯即可,所以 DatagramPacket 中蕴含的数据曾经够用了。

DatagramChannel 是用来传递 DatagramPacket 的,因为 DatagramChannel 是一个接口,所以个别应用 NioDatagramChannel 作为真正应用的类。

String 和 ByteBuf 的转换

之前咱们讲到过,netty 中的 channel 只承受 ByteBuf 数据类型,如果间接写入 String 会报错,之前的系列文章中,咱们讲过两种解决办法,第一种是应用 ObjectEncoder 和 ObjectDecoder 在写入 ByteBuf 之前,对对象进行序列化,这一种不仅适宜 String,也适宜 Object 对象。

第二种是应用 StringEncoder 和 StringDecoder 专门解决 String 的 encode 和 decode,这种解决只能解决 String 的转换,对 Object 有效。

如果你不想应用这些 encoder 和 decoder 还能够间接应用 ByteBuf 和 String 进行转换。

比方要将 String 写入 ByteBuf 能够调用 Unpooled.copiedBuffer 的命令如下:

Unpooled.copiedBuffer("开始播送", CharsetUtil.UTF_8)

将 ByteBuf 转换成为 String 则能够调用:

byteBuf.toString(CharsetUtil.UTF_8)

构建 DatagramPacket

DatagramPacket 总共能够承受三个参数,别离是要发送的数据 data, 要接管数据包的地址和要发送数据包的地址。

这里咱们并不关怀发送数据包的地址,那么只须要两个参数即可,对于客户端来说,咱们发送一个”开始播送“的音讯给服务器端,通知服务器端能够向客户发送回复音讯了,如下所示:

new DatagramPacket(Unpooled.copiedBuffer("开始播送", CharsetUtil.UTF_8),
                    SocketUtils.socketAddress("255.255.255.255", PORT))

上咱们应用 SocketUtils.socketAddress 创立了一个非凡的地址,255.255.255.255 是一个非凡的播送地址,意味着所有的主机,因为咱们的客户端并不知道服务器的地址,所以应用 255.255.255.255 来播送。

构建好的 DatagramPacket,外面有一个 sender() 办法,能够用来获取客户端的地址,所以在服务器端能够这样构建要发送的 packge:

new DatagramPacket(Unpooled.copiedBuffer("播送:" + nextQuote(), CharsetUtil.UTF_8), packet.sender())

启动客户端和服务器

UDP 的客户端和服务器启动和 socket 略微有所不同,如果是 socket,那么应用的 channel 是 NioSocketChannel,如果是 UDP,则应用的是 NioDatagramChannel。如下是服务器端启动的代码:

EventLoopGroup group = new NioEventLoopGroup();
        try {Bootstrap b = new Bootstrap();
            b.group(group)
             .channel(NioDatagramChannel.class)
             .option(ChannelOption.SO_BROADCAST, true)
             .handler(new UDPServerHandler());

            b.bind(PORT).sync().channel().closeFuture().await();
        } finally {group.shutdownGracefully();
        }

留神,这里咱们须要设置 ChannelOption.SO_BROADCAST 为 true,因为 UDP 是以播送的模式发送音讯的。

客户端的实现和 socket 略微有所不同,上面是客户端的启动实现:

 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 来说,并不存在地址绑定一说,所以上 Bootstrap 调用 bind(0)。

总结

本文解说了 netty 中 UDP 协定的实现,UDP 相较于 Socket 连贯而言更加简略。

本文的例子能够参考:learn-netty4

本文已收录于 http://www.flydean.com/11-netty-udp/

最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!

欢送关注我的公众号:「程序那些事」, 懂技术,更懂你!

退出移动版