Internet 协议集支持一个无连接的传输协议,该协议称为用户数据报协议(UDP,User Datagram Protocol)。UDP 为应用程序提供了一种无需建立连接就可以发送封装的 IP 数据包的方法。RFC 768 [1] 描述了 UDP。
Internet 的传输层有两个主要协议,互为补充。无连接的是 UDP,它除了给应用程序发送数据包功能并允许它们在所需的层次上架构自己的协议之外,几乎没有做什么特别的事情。面向连接的是 TCP,该协议几乎做了所有的事情。
UDP 是User Datagram Protocol的简称, 中文名是用户数据报协议,是OSI(Open System Interconnection,开放式系统互联) 参考模型中一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务,IETF RFC 768 [1] 是UDP的正式规范。UDP在IP报文的协议号是17。
UDP协议与TCP协议一样用于处理数据包,在OSI模型中,两者都位于传输层,处于IP协议的上一层。UDP有不提供数据包分组、组装和不能对数据包进行排序的缺点,也就是说,当报文发送之后,是无法得知其是否安全完整到达的。UDP用来支持那些需要在计算机之间传输数据的网络应用。包括网络视频会议系统在内的众多的客户/服务器模式的网络应用都需要使用UDP协议。UDP协议从问世至今已经被使用了很多年,虽然其最初的光彩已经被一些类似协议所掩盖,但即使在今天UDP仍然不失为一项非常实用和可行的网络传输层协议。
许多应用只支持UDP,如:多媒体数据流,不产生任何额外的数据,即使知道有破坏的包也不进行重发。当强调传输性能而不是传输的完整性时,如:音频和多媒体应用,UDP是最好的选择。在数据传输时间很短,以至于此前的连接过程成为整个流量主体的情况下,UDP也是一个好的选择。
以上为百度百科,提前先科普一下:
组播地址
224.0.0.0~224.0.0.255 为预留的组播地址(永久组地址),地址224.0.0.0保留不做分配,其它地址供路由协议使用;
224.0.1.0~224.0.1.255 是公用组播地址,可以用于Internet;欲使用需申请。
224.0.2.0~238.255.255.255 为用户可用的组播地址(临时组地址),全网范围内有效;
239.0.0.0~239.255.255.255 为本地管理组播地址,仅在特定的本地范围内有效。
接收端
package com.example.netty.test3;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.UnpooledByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
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;
public class UdpRecv {
public static Integer SPORT = 1112;
public static Integer DPORT = 1111;
public static void main(String[] args) {
NioEventLoopGroup group = new NioEventLoopGroup();
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group)
.channel(NioDatagramChannel.class)
.option(ChannelOption.SO_BROADCAST, true)
.handler(new ChannelInitializer() {
@Override
protected void initChannel(NioDatagramChannel ch) throws Exception {
// TODO Auto-generated method stub
ch.pipeline().addLast(new MyHandlerRece());
}
});
try {
Channel channel = bootstrap.bind(SPORT).sync().channel();
channel.closeFuture().sync();
group.shutdownGracefully();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class MyHandlerRece extends SimpleChannelInboundHandler{
@Override
protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception {
ByteBuf buf = msg.content();
String strMsg = buf.toString(CharsetUtil.UTF_8);
System.out.println("recv : "+strMsg);
InetSocketAddress remoteAddress = new InetSocketAddress("192.168.1.105", UdpRecv.DPORT);
ByteBuf byteBuf1 = new UnpooledByteBufAllocator(false).buffer();
byteBuf1.writeCharSequence("recv send :"+strMsg, Charset.forName("utf-8"));
DatagramPacket packet = new DatagramPacket(byteBuf1, remoteAddress);
ctx.writeAndFlush(packet);
}
}
发送端
package com.example.netty.test3;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import java.util.concurrent.TimeUnit;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.UnpooledByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
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;
public class UpdSend {
public static Integer SPORT = 1111;
public static Integer DPORT = 1112;
public static void main(String[] args) {
NioEventLoopGroup group = new NioEventLoopGroup();
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group).channel(NioDatagramChannel.class).option(ChannelOption.SO_BROADCAST, true)
.handler(new ChannelInitializer() {
@Override
protected void initChannel(NioDatagramChannel ch) throws Exception {
// TODO Auto-generated method stub
ch.pipeline().addLast(new MyHandlerSend());
}
});
try {
Channel channel = bootstrap.bind(SPORT).sync().channel();
InetSocketAddress remoteAddress = new InetSocketAddress("192.168.1.105", DPORT);
for (int i = 0; i < 5; i++) {
TimeUnit.SECONDS.sleep(1);
String msg = "send " + i;
ByteBuf byteBuf1 = new UnpooledByteBufAllocator(false).buffer();
byteBuf1.writeCharSequence(msg, Charset.forName("utf-8"));
DatagramPacket packet = new DatagramPacket(byteBuf1, remoteAddress);
channel.writeAndFlush(packet);
System.out.println(msg);
}
channel.closeFuture().sync();
group.shutdownGracefully();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class MyHandlerSend extends SimpleChannelInboundHandler {
@Override
protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception {
ByteBuf buf = msg.content();
String strMsg = buf.toString(CharsetUtil.UTF_8);
System.out.println("Recv Send :" + strMsg);
}
}
接收端
package com.example.netty.test3;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.UnpooledByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
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;
public class UdpRecv {
public static Integer SPORT = 1112;
public static Integer DPORT = 1111;
public static void main(String[] args) {
NioEventLoopGroup group = new NioEventLoopGroup();
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group)
.channel(NioDatagramChannel.class)
.option(ChannelOption.SO_BROADCAST, true)
.handler(new ChannelInitializer() {
@Override
protected void initChannel(NioDatagramChannel ch) throws Exception {
// TODO Auto-generated method stub
ch.pipeline().addLast(new MyHandlerRece());
}
});
try {
Channel channel = bootstrap.bind(SPORT).sync().channel();
channel.closeFuture().sync();
group.shutdownGracefully();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class MyHandlerRece extends SimpleChannelInboundHandler{
@Override
protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception {
ByteBuf buf = msg.content();
String strMsg = buf.toString(CharsetUtil.UTF_8);
System.out.println("recv : "+strMsg);
InetSocketAddress remoteAddress = new InetSocketAddress("255.255.255.255", UdpRecv.DPORT);
ByteBuf byteBuf1 = new UnpooledByteBufAllocator(false).buffer();
byteBuf1.writeCharSequence("recv send :"+strMsg, Charset.forName("utf-8"));
DatagramPacket packet = new DatagramPacket(byteBuf1, remoteAddress);
ctx.writeAndFlush(packet);
}
}
发送端
package com.example.netty.test3;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import java.util.concurrent.TimeUnit;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.UnpooledByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
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;
public class UpdSend {
public static Integer SPORT = 1111;
public static Integer DPORT = 1112;
public static void main(String[] args) {
NioEventLoopGroup group = new NioEventLoopGroup();
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group).channel(NioDatagramChannel.class).option(ChannelOption.SO_BROADCAST, true)
.handler(new ChannelInitializer() {
@Override
protected void initChannel(NioDatagramChannel ch) throws Exception {
// TODO Auto-generated method stub
ch.pipeline().addLast(new MyHandlerSend());
}
});
try {
Channel channel = bootstrap.bind(SPORT).sync().channel();
InetSocketAddress remoteAddress = new InetSocketAddress("255.255.255.255", DPORT);
for (int i = 0; i < 5; i++) {
TimeUnit.SECONDS.sleep(1);
String msg = "send " + i;
ByteBuf byteBuf1 = new UnpooledByteBufAllocator(false).buffer();
byteBuf1.writeCharSequence(msg, Charset.forName("utf-8"));
DatagramPacket packet = new DatagramPacket(byteBuf1, remoteAddress);
channel.writeAndFlush(packet);
System.out.println(msg);
}
channel.closeFuture().sync();
group.shutdownGracefully();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class MyHandlerSend extends SimpleChannelInboundHandler {
@Override
protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception {
ByteBuf buf = msg.content();
String strMsg = buf.toString(CharsetUtil.UTF_8);
System.out.println("Recv Send :" + strMsg);
}
}
server端
package com.example.netty.test4;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.util.Enumeration;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
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;
import io.netty.util.NetUtil;
/**
* UDP组播 Server
* @author yuxuan
*
*/
public class Mserver {
public static void main(String[] args) {
System.setProperty("java.net.preferIPv4Stack", "true");//只使用IPV4
// 组播地址
InetSocketAddress groupAddress = new InetSocketAddress("224.2.1.1", 9000);
EventLoopGroup group = new NioEventLoopGroup();
try {
NetworkInterface ni = NetUtil.LOOPBACK_IF;
Enumeration addresses = ni.getInetAddresses();
InetAddress localAddress = null;
while (addresses.hasMoreElements()) {
InetAddress address = addresses.nextElement();
if (address instanceof Inet4Address){
localAddress = address;
}
}
System.out.println(localAddress);
Bootstrap bootstrap = new Bootstrap();
//设置NioDatagramChannel
bootstrap.group(group).channel(NioDatagramChannel.class)
.localAddress(localAddress,groupAddress.getPort())
//设置Option 组播
.option(ChannelOption.IP_MULTICAST_IF, ni)
//设置Option 地址
.option(ChannelOption.IP_MULTICAST_ADDR, localAddress)
//设置地址
.option(ChannelOption.SO_REUSEADDR, true)
.handler(new ChannelInitializer() {
@Override
public void initChannel(NioDatagramChannel ch) throws Exception {
ChannelPipeline addLast = ch.pipeline().addLast();
addLast.addLast(new SimpleChannelInboundHandler() {//接收信息处理
@Override
protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception {
// 打印一句话
System.out.println(msg.sender()+" >>> "+new String(msg.content().toString(CharsetUtil.UTF_8)));
}
});
}
});
//获取NioDatagramChannel
NioDatagramChannel channel = (NioDatagramChannel) bootstrap.bind(groupAddress.getPort()).sync().channel();
//加入组
channel.joinGroup(groupAddress, ni).sync();
//关闭Channel
channel.closeFuture().await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
group.shutdownGracefully();//优雅退出
}
}
}
client端
package com.example.netty.test4;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.util.Enumeration;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
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;
import io.netty.util.NetUtil;
/**
* UPD组播 Client
* @author yuxuan
*
*/
public class MClient {
public static void main(String[] args) {
System.setProperty("java.net.preferIPv4Stack", "true");// 只使用IPV4
// 组播地址
InetSocketAddress groupAddress = new InetSocketAddress("224.2.1.1", 9000);
EventLoopGroup group = new NioEventLoopGroup();
try {
NetworkInterface ni = NetUtil.LOOPBACK_IF;
Enumeration addresses = ni.getInetAddresses();
InetAddress localAddress = null;
while (addresses.hasMoreElements()) {
InetAddress address = addresses.nextElement();
if (address instanceof Inet4Address) {
localAddress = address;
}
}
Bootstrap b = new Bootstrap();
// 设置Channel
b.group(group).channel(NioDatagramChannel.class)
// 设置LocalAddress
.localAddress(localAddress, groupAddress.getPort())
// 设置Option 组播
.option(ChannelOption.IP_MULTICAST_IF, ni)
// 设置Option 重复地址
.option(ChannelOption.SO_REUSEADDR, true)
// 设置Handler
.handler(new ChannelInitializer() {
@Override
protected void initChannel(NioDatagramChannel ch) throws Exception {
ch.pipeline().addLast(new SimpleChannelInboundHandler() {
@Override
protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg)
throws Exception {
// 打印一句话
System.out.println(msg.content().toString(CharsetUtil.UTF_8));
}
});
}
});
// 获取Channel
Channel ch = b.bind().sync().channel();
// 往组播地址中发送数据报
ch.writeAndFlush(new DatagramPacket(Unpooled.copiedBuffer("hello world", CharsetUtil.UTF_8), groupAddress))
.sync();// 发送数据
// 关闭Channel
ch.close().awaitUninterruptibly();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
group.shutdownGracefully();
}
}
}
这里需要注意,组播的话需要提前加入一个组。