目录

Java网络编程UDP通信篇

Java网络编程:UDP通信篇

https://i-blog.csdnimg.cn/blog_migrate/99057e147e22977d8738bc97c958b193.gif


目录


UDP协议

对于UDP协议,这里简单做一下介绍:

在TCP/IP协议簇中,用户数据报协议(UDP)是传输层的一个主要协议之一,它与传输控制协议(TCP)一起构成了互联网的基础。UDP具有以下几个主要特点:

  1. 无连接 :UDP是一个无连接的协议,这意味着在通信之前不需要建立连接。每个数据包独立传输,没有握手过程。这使得UDP的传输延迟较低,适合需要快速传输数据的应用场景。
  2. 不可靠传输 :UDP不保证数据的可靠传输。数据包可能会丢失、重复或乱序到达。协议本身不提供错误检测和重传机制。如果需要可靠性,必须在应用层实现。
  3. 面向报文 :UDP是面向报文的协议。发送方将数据分成独立的报文,每个报文包含完整的消息。接收方按报文接收数据,报文的边界在接收时保持不变。
  4. 低开销 :由于UDP没有连接建立、维护和终止的开销,也没有复杂的错误控制和流量控制机制,其报头信息较少,仅包含源端口、目标端口、长度和校验和。这使得UDP的开销非常低,适合需要高效传输的应用。
  5. 支持广播和多播 :UDP支持广播和多播,这意味着可以将数据包发送到一个或多个网络中的所有主机。这在某些网络应用中非常有用,例如视频流和在线游戏。
  6. 实时性好 :由于没有连接建立和维护的开销,加上较低的协议处理时间,UDP适合实时性要求高的应用,如视频会议、语音通信和在线游戏。
  7. 简单性 :UDP协议相对简单,实现和使用都比较方便。应用程序可以直接在UDP之上构建,并根据需要添加错误处理、重传等机制。

适用场景

  • 实时应用 :如视频流、语音通信、在线游戏等,要求低延迟和实时性,数据丢失影响较小。
  • 简单查询服务 :如DNS查询,发送一个请求并期望快速响应,偶尔的丢包可以通过重试解决。
  • 广播和多播 :如网络发现、服务公告等,需要将消息发送给多个主机。

Java中的UDP通信

市面上大部分Java应用存在着大量的通信交流的需求,那了解了UDP协议的相关信息和使用场景后,对于Java程序我们该如何来实现通信呢?

在Java中实现UDP通信涉及两个主要类: DatagramSocketDatagramPacket

DatagramSocket

DatagramSocket 类用于创建和管理UDP套接字。它负责发送和接收数据包,并提供了基本的网络通信功能。

主要功能包括:

  • 绑定到特定的IP地址和端口。
  • 发送和接收 DatagramPacket
  • 管理网络连接的基本设置(例如超时、缓冲区大小)。

主要方法

  • DatagramSocket()
    创建一个绑定到任意可用端口的套接字。
  • DatagramSocket(int port)
    创建一个绑定到指定端口的套接字。
  • DatagramSocket(int port, InetAddress laddr)
    创建一个绑定到指定端口和本地地址的套接字。
  • send(DatagramPacket p)
    发送数据包。
  • receive(DatagramPacket p)
    接收数据包。
  • close()
    关闭套接字。

更多详细的方法和参数讲解可以查看 oracle 官方的API文档:

这里是中文版本的:

DatagramPacket

DatagramPacket 类用于表示一个数据包。它包含发送或接收的数据,以及目标或来源的IP地址和端口。

主要功能包括:

  • 封装数据(字节数组)。
  • 存储发送或接收数据包的目标或来源信息(IP地址和端口)。

主要方法

  • DatagramPacket(byte[] buf, int length)
    创建用于接收数据的数据包。
  • DatagramPacket(byte[] buf, int length, InetAddress address, int port)
    创建用于发送数据的数据包。
  • getData()
    获取数据包中的数据。
  • getLength()
    获取数据包中数据的长度。
  • getAddress()
    获取数据包的目标或来源地址。
  • getPort()
    获取数据包的目标或来源端口。
  • setData(byte[] buf)
    设置数据包中的数据。
  • setLength(int length)
    设置数据包中数据的长度。
  • setAddress(InetAddress address)
    设置数据包的目标地址。
  • setPort(int port)
    设置数据包的目标端口。

笔者这里还是将官方的API文档和对应的中文文档给出:

DatagramSocket 主要通过 DatagramPacket 来传输和接收数据。在UDP通信中, DatagramPacket 用于封装数据和相关信息(如目标地址和端口),而 DatagramSocket 则用于实际的发送和接收操作。

举个点外卖的例子来说明,假如今天是疯狂星期四,小李想要点个肯德基的芝士汉堡, DatagramSocket 就相对于是肯德基的大门以及小李家的大门, DatagramPacket 就相对于是外卖小哥,小李点的汉堡等食品就相对于是要传输的数据,当肯德基做好汉堡后,外卖小哥通过肯德基的大门的地址信息( DatagramSocket )拿到汉堡( 数据 ),然后由外卖小哥将食品包装好,到小李家楼下后通过小李家的门牌号的信息( DatagramSocket )找到小李,并且将汉堡交付给小李。

另外,这里对套接字需要简单的做一个解释:

套接字(Socket)是网络通信的基本组件,它提供了一种机制,使得计算机能够通过网络进行数据传输。套接字是一个抽象概念,用于表示网络通信的一个端点。无论是TCP还是UDP通信,套接字都是必不可少的。


UDP客户端-服务端代码实现

服务器端和客户端在代码实现方面是非常简单的,在前文中有说到:UDP不是面向连接的而且协议本身就很简单。因此在实现方面需要做的功能也很少,大致可以分为以下几步:

  • 创建套接字(DatagramSocket)。
  • 发送(Send)和接收(Receive)数据包(DatagramPacket)。
  • 关闭(Close)套接字。

还是拿刚才买汉堡的例子,我们就可以这样来实现:

UDP客户端:

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Arrays;

public class UDPClient {
    public static void main(String[] args) throws IOException {
        // 要发送的信息
        String messg = "我是小李,我想点一个芝士汉堡";
        // 建立Socket
        DatagramSocket socket = new DatagramSocket();
        // 建立收发容器
        byte[] sendData;
        byte[] receiveData = new byte[1024];
        // 发送数据包
        sendData = messg.getBytes();
        InetAddress serverAddress = InetAddress.getByName("localhost");
        DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, serverAddress, 9999);
        socket.send(sendPacket);
        // 接收数据包
        DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
        socket.receive(receivePacket);
        String receivedMessage = new String(receivePacket.getData(), 0, receivePacket.getLength());
        System.out.println("Received from Server: " + receivedMessage);
        // 关闭套接字
        socket.close();
    }
}

UDP服务端:

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Arrays;

public class UDPServer {
    public static void main(String[] args) throws IOException {
        // 要发送的信息
        String messg = "这里是肯德基,您的芝士汉堡已经制作完毕,祝您用餐愉快";
        // 建立Socket
        DatagramSocket socket = new DatagramSocket(9999);
        try {
            // 建立收发容器
            byte[] sendData;
            byte[] receiveData = new byte[1024];
            // 接收数据包
            DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
            socket.receive(receivePacket);
            String receivedMessage = new String(receivePacket.getData(), 0, receivePacket.getLength());
            System.out.println("Received from Client: " + receivedMessage);
            // 发送数据包
            sendData = messg.getBytes();
            InetAddress clientAddress = receivePacket.getAddress();
            int clientPort = receivePacket.getPort();
            DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, clientAddress, clientPort);
            socket.send(sendPacket);
        } finally {
            // 关闭套接字
            if (socket != null && !socket.isClosed()) {
                socket.close();
            }
        }
    }
}

上述只是一个非常简单的例子,实现了UDP通信中的一发一收的功能。要实现更丰富的功能也只需要稍微改一改就行,比如加上while循环就可以使得通信可以不间断,一直发消息一直收消息,也可以加上文件读写的操作使得用户的输入可以更多样化。




https://i-blog.csdnimg.cn/blog_migrate/f36eb0918a12881f6d4fab653751cf47.png 本次的分享就到此为止了,希望我的分享能给您带来帮助,创作不易也欢迎大家三连支持,你们的点赞就是博主更新最大的动力! https://i-blog.csdnimg.cn/blog_migrate/ae0697f3e6a97d896b01edac317f898c.png 如有不同意见,欢迎评论区积极讨论交流,让我们一起学习进步! https://i-blog.csdnimg.cn/blog_migrate/8ab7d9089b6842ea49b47db52edb6707.png 有相关问题也可以私信博主,评论区和私信都会认真查看的,我们下次再见 https://i-blog.csdnimg.cn/blog_migrate/8ab7d9089b6842ea49b47db52edb6707.png