专栏首页Java 学习【Java】21 基于 UDP 的网络编程

【Java】21 基于 UDP 的网络编程

Java 提供了 DatagramSocket 对象作为基于 UDP 协议的 Socket,使用 DatagramPacket 代表 DatagramSocket 发送、接收的数据报。

1.1 UDP 基础

  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 协议将数据报转换成实际数据内容。


1.2 UDP 通信相关类

1.2.1 DatagramSocket 类

  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 对象向外发送数据报

1.2.2 DatagramPacket 类

  使用 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


1.3 实现 UDP 通信

1.3.1 UDP 通信分析

发送端 ① 创建 DatagramSocket 对象(创建一个码头) ② 创建 DatagramPacket 对象并指定IP和端口号(装箱并集装箱贴目的地和接收港编号) ③ 调用 send() 方法发送(发送集装箱) ④ 释放资源(拆码头) 接收端 ① 创建 DatagramSocket 对象并指定端口号(创建一个码头并编号) ② 创建 DatagramPacket 对象,用于接收数据(拆箱) ③ 调用 receive() 方法接收(接收集装箱) ④ 释放资源(拆码头)

1.3.2 客户端

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();
            }
        }
    }
}

1.3.3 服务端

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 可以被动接收数据。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • select 高级查询之连接查询

      笛卡尔乘积是指在数学中,两个集合 X 和 Y 的笛卡尔积(Cartesian product),又称直积,表示为 X×Y,第一个对象是 X 的成员而第二个对...

    Demo_Null
  • MQ 系列之 ActiveMQ 可靠性

    Queue 持久化与生产者有关,所谓持久化就是在 ActiveMQ 凉凉之后,消息会被保留下来,ActiveMQ 再次启动之后会发给消费者,默认 ActiveM...

    Demo_Null
  • vue 渐变色文字

    ☞ 注意 text-fill-color 一般设置为 transparent(透明),然后使用 background-image 渐变颜色来设置文字的背景色,...

    Demo_Null
  • Github之修改用户名

    2016-07-1013:48:05 发表评论 218℃热度 这几天开始正式深入学习Github方面的知识,由于之前的用户名比较随便,所以第一件事就是更改自己...

    timhbw
  • 如何解决代码腐败的味道

    用户7676729
  • 【深度学习】目标检测中 IOU 的概念及计算

    在目标检测当中,有一个重要的概念就是 IOU。一般指代模型预测的 bbox 和 Groud Truth 之间的交并比。

    Frank909
  • Stack - 栈

    为了去野外烧烤,你创建了一堆的任务清单 - 一叠便条。对一叠便条会有如下操作:插入的待办事项放在清单的最前面;读取待办事项时,只读取最上面的,并将其删除。一叠便...

    caoqi95
  • 为什么大家都爱极简主义设计

    简约并不意味着原始,这是两个截然不同的概念。而极简主义设计种大量的留白也并不等同于空。

    宇相
  • UI极简风设计,你需要掌握这几点

    简约并不意味着原始,这是两个截然不同的概念。而极简主义设计种大量的留白也并不等同于空。

    用户5009027
  • chorme模拟微信浏览器

    deepcc

扫码关注云+社区

领取腾讯云代金券