UDP
传输层协议 :User Datagram Protocal
基于报文传输
分类 | TCP | UDP |
---|---|---|
面向连接 | 无连接 | |
只有两端 只能一对一通信 | 可以一对一,一对多,多对一,多对多通信 | |
基于字节流 | 基于报文 | |
重要特性 | 可靠 | 不可爱(尽最大可能交付) |
首部占用空间大 20-60字节之间 | 首部空间小,8字节(记录报文长度) |
UDP的分类
- 单播: 一对一
- 组播:一对多(组播)
- 广播 : 多对多(局域网内的全部)
TCP协议已经尽可能的支持了并发 所以大部分还是使用的TCP协议 除非网络很差的情况下使用UDP
原生的UDP实现
- DatagramSocket 代表通信的一段
- DatagramPacket 是数据的通信格式 报文,
- 在创建的时候 需要明确数据是字节数组 以及另一端的ip地址 端口
- 在接受报文和发送报文前 使用字节数组进行接收和组装
- 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实现
- DatagramSocket 对应 NioDatagramChannel
- java.net.datagramPacket 对应 import io.netty.channel.socket.DatagramPacket
- 无论客户端还是服务端都使用 bootstrap来启动
- 通过调用Bootstrap的localAddress()指定端口号,也可以调用remoeteAddress指定连接地址(ip 端口号)
- 自定义 handler 的使用 ,继承SimpleChannelInboundHandler 泛型声明为datagramPacket 实现channelread0方法来实现逻辑
- 组装datagramPacket 通过byteBuf 加上socketAddress()
- 组装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();
}
}