Java 提供了 DatagramSocket 对象作为基于 UDP 协议的 Socket,使用 DatagramPacket 代表 DatagramSocket 发送、接收的数据报。
UDP 协议是英文 User Datagram Protocol 的缩写,即用户数据报协议,主要用来支持那些需要在计算机之间传输数据的网络连接。UDP 协议从问世至今已经被使用了很多年,虽然 UDP 协议目前应用不如 TCP 协议广泛,但 UDP 协议依然是一个非常实用和可行的网络传输层协议。尤其是在一些实时性很强的应用场景中,比如网络游戏、视频会议等,UDP 协议的快速更具有独特的魅力。 UDP 协议是一种面向非连接的协议,面向非连接指的是在正式通信前不必与对方先建立连接,不管对方状态就直接发送。至于对方是否可以接收到这些数据内容,UDP 协议无法控制,因此说 UDP 协议是一种不可靠的协议。UDP 协议适用于一次只传送少量数据、对可靠性要求不高的应用环境。与 TCP 协议一样,UDP 协议直接位于 IP 协议之上。实际上,IP 协议属于 OSI 参考模型的网络层协议,而 UDP 协议和 TCP 协议都属于传输层协议。 因为 UDP 协议是面向非连接的协议,没有建立连接的过程,因此它的通信效率很高;但也正因为如此,它的可靠性不如 TCP 协议。UDP 协议的主要作用是完成网络数据流和数据报之间的转换。在信息的发送端,UDP 协议将网络数据流封装成数据报,然后将数据报发送出去;在信息的接收端,UDP 协议将数据报转换成实际数据内容。
Java 提供了 DatagramSocket 对象作为基于 UDP 协议的 Socket,但是 DatagramSocket 本身只是码头,不能维护状态,不能产生IO流,它的唯一作用就是接收和发送数据报,Java 使用 DatagramPacket 来代表数据报,DatagramSocket 接收和发送的数据都是通过 DatagramPacket 对象完成的。
public DatagramSocket()
:创建一个 DatagramSocket 实例,并将该对象绑定到本机默认 IP 地址、本机所有可用端口中随机选择的某个端口。
public DatagramSocket(int prot)
:创建一个 DatagramSocket 实例,并将该对象绑定到本机默认 IP 地址、指定端口。
public DatagramSocket(int port, InetAddress laddr)
:创建一个 DatagramSocket 实例,并将该对象绑定到指定 IP 地址、指定端口。
方法名 | 说明 |
---|---|
void receive(DatagramPacket p) | 从该 DatagramSocket 中接收数据报 |
void send(DatagramPacket p) | 从该 DatagramSocket 对象向外发送数据报 |
使用 DatagramSocket 发送数据报时,DatagramSocket 并不知道将该数据报发送到哪里,而是由 DatagramPacket 决定数据报的目的地。就像码头并不知道每个集装箱的目的地,码头只是将这些集装箱发送出去,而集装箱本身包含了该集装箱的目的地。
public DatagramPacket(byte[] buf,int length)
:以一个空数组来创建 DatagramPacket 对象,该对象的作用是接收 DatagramSocket 中的数据。
public DatagramPacket(byte[] buf, int offset, int length)
:以一个空数组来创建 DatagramPacket 对象,并指定接收到的数据放入 buf 数组中时从 offset 开始,最多放 length 个字节。
public DatagramPacket(byte[] buf, int length, InetAddress addr, int port)
:以一个包含数据的数组来创建一个用于发送的 DatagramPacket 对象,创建该 DatagramPacket 对象时还指定了 IP 地址和端口,这就决定了该数据报的目的地。
public DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port)
:以一个包含数据的数组来创建一个用于发送的 DatagramPacket 对象,指定发送 buf 数组中从 offset 开始,总共 length 个字节。
方法名 | 说明 |
---|---|
InetAddress getAddress() | 获取当前 IP |
int getPort() | 获取当前端口号 |
InetAddress.getLocalHost() | 获取本地主机的 InetAddress |
InetAddress.getByName(String host) | 获取指定主机名的 InetAddress |
InetAddress.getByAddress(byte[] addr) | 获取指定 IP 的 InetAddress |
InetAddress.getByAddress(String host, byte[] addr) | 获取指定 主机名 和 IP 的 InetAddress |
发送端 ① 创建 DatagramSocket 对象(创建一个码头) ② 创建 DatagramPacket 对象并指定IP和端口号(装箱并集装箱贴目的地和接收港编号) ③ 调用 send() 方法发送(发送集装箱) ④ 释放资源(拆码头) 接收端 ① 创建 DatagramSocket 对象并指定端口号(创建一个码头并编号) ② 创建 DatagramPacket 对象,用于接收数据(拆箱) ③ 调用 receive() 方法接收(接收集装箱) ④ 释放资源(拆码头)
public class DemoSend { public static void main(String[] args) { DatagramSocket socket = null; try { // 创建 DatagramSocket socket = new DatagramSocket(); // 创建数据 byte[] sendBytes = "你好啊!".getBytes(); // 创建 DatagramPacket DatagramPacket sendPacket = new DatagramPacket(sendBytes, sendBytes.length, InetAddress.getByAddress("xiaolaohu.work", new byte[] { (byte) 47, (byte) 103, 4, (byte) 205 }), 9999); // 发送数据 socket.send(sendPacket); // 接受写回数据 // 创建字节数组 byte[] receiveBytes = new byte[1024]; // 创建 DatagramPacket DatagramPacket receivePacket = new DatagramPacket(receiveBytes, receiveBytes.length); // 接受数据 socket.receive(packet1); // 打印到控制台 System.out.println(new String(receivePacket, 0, receiveBytes.length)); } catch (Exception e) { e.printStackTrace(); } finally { //释放资源 if (socket != null) { socket.close(); } } } }
public class DemoReceive { public static void main(String[] args) { DatagramSocket socket = null; try { // 创建 DatagramSocket socket = new DatagramSocket(9999); // 创建字节数组 byte[] receiveBytes = new byte[1024]; // 创建 DatagramPacket DatagramPacket receivePacket = new DatagramPacket(receiveBytes, receiveBytes.length); // 接受数据 socket.receive(receivePacket); //打印到控制台 System.out.println(new String(receiveBytes, 0, receiveBytes.length)); // 回写消息 // 创建数据 byte[] sendBytes = "收到了".getBytes(); // 创建 DatagramPacket DatagramPacket sendPacket = new DatagramPacket(sendBytes, sendBytes.length, receivePacket.getAddress(), receivePacket.getPort()); // 发送 socket.send(sendPacket); } catch (IOException e) { e.printStackTrace(); } finally { // 释放资源 if (socket != null) { socket.close(); } } } }
从上述代码可以看出使用 UDP 协议时,实际上并没有明显的服务端和客户端,因为两方都需要先建立一个 DatagramSocket 对象,用来接收或发送数据报,然后使用 DatagramPacket 对象作为传输数据的载体。通常固定 IP 地址、固定端口的 DatagramSocket 对象被称为服务端,因为该 DatagramSocket 可以被动接收数据。
本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。
我来说两句