简介
在之前的系列文章中,咱们到了应用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/
最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!
欢送关注我的公众号:「程序那些事」,懂技术,更懂你!