跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像AI 生图工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Javajava

Java 网络编程:UDP 数据报套接字编程

介绍 Java 网络编程基础,涵盖 Socket 套接字概念及 TCP/UDP 协议区别。重点讲解 UDP 数据报套接字(DatagramSocket)和数据报包(DatagramPacket)的 API 用法,并提供回显服务器与客户端的完整代码示例,演示 UDP 通信的实现流程。

RedisGeek发布于 2026/3/26更新于 2026/7/1750 浏览
Java 网络编程:UDP 数据报套接字编程

一、网络编程简介

网络编程,指网络上的主机,通过不同的进程,以编程的方式实现网络通信(或称为网络数据传输)。

网络编程涉及基本概念:

一次网络数据传输时: 发送端:数据的发送方进程,称为发送端。发送端主机即网络通信中的源主机。 接收端:数据的接收方进程,称为接收端。接收端主机即网络通信中的目的主机。 收发端:发送端和接收端两端,也简称为收发端。

请求和响应: 一般来说,获取一个网络资源,涉及到两次网络数据传输: 第一次:请求数据的发送。 第二次:响应数据的发送。

客户端和服务端 服务端:在常见的网络数据传输场景下,把提供服务的一方进程,称为服务端,可以提供对外服务。 客户端:获取服务的一方进程,称为客户端。

二、Socket 套接字

Socket 套接字,是由系统提供用于网络通信的技术,是基于 TCP/IP 协议的网络通信的基本操作单元。基于 Socket 套接字的网络程序开发就是网络编程。

Socket 套接字主要针对传输层协议划分为如下三类:

  1. 流套接字:使用传输层 TCP 协议。
  2. 数据报套接字:使用传输层 UDP 协议。
  3. 原始套接字:用于自定义传输层协议。

三、TCP/UDP 简介

socket api:传输层提供给应用层的 API。 传输层的两个核心协议是:TCP 与 UDP 协议。

  • TCP 协议:有连接,可靠传输,面向字节流,全双工的协议。
  • UDP 协议:无连接,不可靠传输,面向数据报,全双工的协议。

3.1 有连接 vs 无连接

有/无连接:是一个抽象的概念,虚拟的逻辑上的连接。就像前面的链表的学习一样,物理上不连续,但通过节点之间的关联使其逻辑上连续。

TCP 协议中:保存了对端的信息,让两个通信之间的设备有连接。就如 AB 通信,A 保存 B 信息,B 保存 A 信息。

UDP 协议中:UDP 本身不保存对端信息,但可以自己使用代码保存。

3.2 可靠传输 vs 不可靠传输

丢包:网络上数据发生丢失的情况就是丢包。

传输中丢包情况造成原因:

  1. 当光/电/电磁信号,受到外界的干扰。
  2. 网络世界是通过交换机,路由器组建起来的。而交换机,路由器就像十字路口一样,当某个时间点,实际转发的数据超过设备能转发的上限的时候,就会'堵车',造成丢包。

可靠传输:不是保证数据报 100% 到达,不造成一点丢失。而是尽可能提高传输成功的概率,如果丢包还会进行记录。

不可靠传输:在发出数据后就不管了。

3.3 面向字节流 vs 面向数据报

面向数据流:读写数据(读–>接收数据,写–> 发送数据)的时候,以字节为单位。支持读写任意长度,有粘包问题。 面向数据报:读写数据(读–>接收数据,写–> 发送数据)的时候,以一个数据报为单位。有长度限制。

3.4 通信模式

全双工:读写数据(读–>接收数据,写–> 发送数据),支持双向通信,能读能写。 半双工:只支持单向通信,要么读要么写。

四、UDP 数据报套接字编程

计算机中的文件通常是一个广义的概念,文件除了指代一些我们常说的文件外,还能指代一些硬件设备。操作系统管理硬件设备也是抽象成文件。

4.1 API 介绍

4.1.1 DatagramSocket 类

DatagramSocket 是 UDP Socket,用于发送和接收 UDP 数据报。

4.1.1.1 构造方法
方法签名方法说明
public DatagramSocket() throws SocketException创建一个 UDP 数据报套接字的 Socket,绑定到本机任意一个随机端口(一般用于客户端)
public DatagramSocket(int port) throws SocketException创建一个 UDP 数据报套接字的 Socket,绑定到本机指定的端口(一般用于服务端)
public DatagramSocket(int port, InetAddress laddr) throws SocketException创建一个 UDP 数据报套接字的 Socket,绑定到指定的 IP 即 laddr 和端口 port
public DatagramSocket(SocketAddress bindaddr) throws SocketException创建一个 UDP 数据报套接字的 Socket,绑定到 bindaddr 指定的 IP 和端口
4.1.1.2 主要方法
方法签名作用
public void send(DatagramPacket p) throws IOException从此套接字发送数据报包(不会阻塞等待,直接发送)
public synchronized void receive(DatagramPacket p) throws IOException从此套接字接收数据报(如果没有接收到数据报,该方法会阻塞等待)
public void close()关闭此数据报套接字
4.1.2 DatagramPacket 类

DatagramPacket 是 UDP Socket 发送和接收的数据报。

4.1.2.1 构造方法
方法签名作用
public DatagramPacket(byte[] buf, int length)构造一个 DatagramPacket 用来接收数据报,接收的数据保存在字节数组(第一个参数 buf)中,接收指定长度(第二个参数 length)
public DatagramPacket(byte[] buf, int offset, int length)构造一个 DatagramPacket 用来接收数据报,接收的数据保存在字节数组(第一个参数 buf)中,接收指定长度(第二个参数 length)从 buf 的下标 offset 位置开始接收
public DatagramPacket(byte[] buf[], int offset, int length, SocketAddress address)构造一个 DatagramPacket 用来发送数据报,发送的数据为字节数组(第一个参数 buf)中,从 offset 到指定长度(第二个参数 length)。address 指定目的主机的 IP 和端口号
public DatagramPacket(byte[] buf[], int offset, int length, InetAddress address, int port)构造一个 DatagramPacket 用来发送数据报,发送的数据为字节数组(第一个参数 buf)中,从 0 到指定长度(第二个参数 length)。address 指定目的主机的 IP,port 指定目的主机的端口号
public DatagramPacket(byte[] buf[], int length, SocketAddress address)构造一个 DatagramPacket 用来发送数据报,发送的数据为字节数组(第一个参数 buf)中,从 0 到指定长度(第二个参数 length)。address 指定目的主机的 IP 和端口号
public DatagramPacket(byte[] buf[], int length, InetAddress address, int port)构造一个 DatagramPacket 用来接收数据报,接收的数据保存在字节数组(第一个参数 buf)中,接收指定长度(第二个参数 length)address 指定目的主机的 IP,port 指定目的主机的端口号
4.1.2.2 主要方法
方法签名作用
public synchronized byte[] getData()获取数据报中的数据
public synchronized int getPort()从接收的数据报中,获取发送端主机的端口号;或从发送的数据报中,获取接收端主机端口号
public synchronized InetAddress getAddress()从接收的数据报中,获取发送端主机 IP 地址;或从发送的数据报中,获取接收端主机 IP 地址
4.1.3 使用上述类创建回显服务器 - 客户端

回显:请求是啥,响应就是啥。

4.1.3.1 回显服务器 UdpEchoServer
  1. 先创建一个成员变量:Socket 对象,用于接收发送数据报。private DatagramSocket socket = null;
  2. 构造方法,指定一个固定端口号给服务器使用,将 Socket 使用这个端口号实例化。
public UdpEchoServer(int port) throws SocketException {
    socket = new DatagramSocket(port);
}
  1. 接下来在 start 方法中编写服务器实现逻辑。由于服务器是要 7*24 小时工作的,所以在一个死循环中实现。
  2. 读取请求并解析; 4.1 构造一个 DatagramPacket 对象,初始化为 0(不是 null),用于保存 UDP 的载荷部分。 DatagramPacket requestPacket = new DatagramPacket(new byte[2024], 2024); 4.2 读取请求 socket.receive(requestPacket); 4.3 把读取到有效数据的解析为字符串。 通过 getData 方法获取 DatagramPacket 中的字节数组,getLength 方法获取 DatagramPacket 有效数据长度,根据字节数组构造字符串。 String request = new String(requestPacket.getData(), 0, requestPacket.getLength());
  3. 根据请求计算响应,由于是回显服务器,直接请求就是响应。
String response = process(request);
private String process(String request) {
    return request;
}
  1. 把响应返回给客户端,通过 getBytes 方法拿到字符串中的字节数据,getBytes().length 拿到字节长度,getSocketAddress 方法拿到客户端的端口和 IP。
socket.send(new DatagramPacket(request.getBytes(), request.getBytes().length, requestPacket.getSocketAddress()));
  1. 打印一个日志记录此次交互过程。
System.out.printf("[%s : %d], request:%s , response:%s\n", requestPacket.getAddress().toString(), requestPacket.getPort(), request, response);
  1. 总代码
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

public class UdpEchoServer {
    // 先创建一个成员变量:Socket 对象,用于接收发送数据报
    private DatagramSocket socket = null;

    // 构造方法,指定一个固定端口号给服务器使用,将 Socket 使用这个端口号实例化
    public UdpEchoServer(int port) throws SocketException {
        socket = new DatagramSocket(port);
    }

    public void start() throws IOException {
        while (true) {
            // 构造一个 DatagramPacket 对象,初始化为 0(不是 null),用于保存 UDP 的载荷部分。
            DatagramPacket requestPacket = new DatagramPacket(new byte[2024], 2024);
            // 接收请求
            socket.receive(requestPacket);
            // 把读取到有效数据的解析为字符串
            String request = new String(requestPacket.getData(), 0, requestPacket.getLength());
            // 计算响应
            String response = process(request);
            // 把响应返回给客户端
            socket.send(new DatagramPacket(request.getBytes(), request.getBytes().length, requestPacket.getSocketAddress()));
            // 打印一个日志
            System.out.printf("[%s : %d], request:%s , response:%s\n", requestPacket.getAddress().toString(), requestPacket.getPort(), request, response);
        }
    }

    private String process(String request) {
        return request;
    }

    public static void main(String[] args) throws IOException {
        UdpEchoServer server = new UdpEchoServer(6666);
        server.start();
    }
}
4.1.3.2 回显客户端 UdpEchoClient
  1. 先创建一个成员变量:Socket 对象,用于接收发送数据报 private DatagramSocket socket = null;
  2. UDP 本身不保存对端的信息,就自己的代码中保存一下。
private String serverIp;
private int port;
  1. 构造方法是要指定访问的服务器的地址。
public UdpEchoClient(String serverIp, int port) throws SocketException {
    this.serverIp = serverIp;
    this.port = port;
    socket = new DatagramSocket();
}
  1. 从控制台读取用户输入的内容。
System.out.println("请输入要传输的内容");
Scanner scanner = new Scanner(System.in);
if (!scanner.hasNext()) {
    break;
}
String request = scanner.next();
  1. 发送数据报,把请求发送给服务器,需要构造 DatagramPacket 对象。构造过程中,不光要构造载荷,还要设置服务器的 IP 和端口号。
socket.send(new DatagramPacket(request.getBytes(), request.getBytes().length, InetAddress.getByName(serverIp), port));
  1. 接收服务器的响应
DatagramPacket responsePacket = new DatagramPacket(new byte[2024], 2024);
socket.receive(responsePacket);
  1. 从服务器读取的数据进行解析,打印出来。
String response = new String(responsePacket.getData(), 0, responsePacket.getData().length);
System.out.println(response);
  1. 总代码
import java.io.IOException;
import java.net.*;
import java.util.Scanner;

public class UdpEchoClient {
    // 先创建一个成员变量:Socket 对象,用于接收发送数据报
    private DatagramSocket socket = null;
    // UDP 本身不保存对端的信息,自己的代码中保存一下
    private String serverIp;
    private int port;

    public UdpEchoClient(String serverIp, int port) throws SocketException {
        this.serverIp = serverIp;
        this.port = port;
        socket = new DatagramSocket();
    }

    public void start() throws IOException {
        while (true) {
            // 1. 从控制台读取用户输入的内容。
            System.out.println("请输入要传输的内容");
            Scanner scanner = new Scanner(System.in);
            if (!scanner.hasNext()) {
                break;
            }
            String request = scanner.next();
            // 发送数据报。把请求发送给服务器,需要构造 DatagramPacket 对象。构造过程中,不光要构造载荷,还要设置服务器的 IP 和端口号。
            socket.send(new DatagramPacket(request.getBytes(), request.getBytes().length, InetAddress.getByName(serverIp), port));
            // 接收服务器的响应
            DatagramPacket responsePacket = new DatagramPacket(new byte[2024], 2024);
            socket.receive(responsePacket);
            // 从服务器读取的数据进行解析,打印出来。
            String response = new String(responsePacket.getData(), 0, responsePacket.getData().length);
            System.out.println(response);
        }
    }

    public static void main(String[] args) throws IOException {
        UdpEchoClient client = new UdpEchoClient("127.0.0.1", 6666);
        client.start();
    }
}

目录

  1. 一、网络编程简介
  2. 二、Socket 套接字
  3. 三、TCP/UDP 简介
  4. 3.1 有连接 vs 无连接
  5. 3.2 可靠传输 vs 不可靠传输
  6. 3.3 面向字节流 vs 面向数据报
  7. 3.4 通信模式
  8. 四、UDP 数据报套接字编程
  9. 4.1 API 介绍
  10. 4.1.1 DatagramSocket 类
  11. 4.1.1.1 构造方法
  12. 4.1.1.2 主要方法
  13. 4.1.2 DatagramPacket 类
  14. 4.1.2.1 构造方法
  15. 4.1.2.2 主要方法
  16. 4.1.3 使用上述类创建回显服务器 - 客户端
  17. 4.1.3.1 回显服务器 UdpEchoServer
  18. 4.1.3.2 回显客户端 UdpEchoClient
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • FPGA 基础概念与架构面试题详解
  • JVM 对象引用定位机制:句柄池与直接指针
  • 前缀和算法详解:如何用空间换时间优化区间查询
  • C++ 面试题常用总结详解
  • Blazor + .NET MAUI 跨平台桌面应用开发实战
  • C++ I/O 流详解:文件读写与字符串流
  • 前端 CI/CD 流程:构建与自动化部署最佳实践
  • 机器人 DH 参数模型与正运动学详解
  • macOS Tahoe 26.2 更新详解:12 项关键改进与体验优化
  • Python 入门教程:从零开始到精通详解
  • OpenClaw 配置飞书机器人指南
  • VS Code GitHub Copilot 安装与核心配置实战
  • Midjourney 第三方 API 服务技术原理与合规边界
  • Whisper-large-v3 云端部署详细步骤
  • RuoYi-Vue3 跨平台实践:基于 Electron 的桌面化迁移方案
  • 二分答案专题实战:木材加工与砍树问题解析
  • Claude Skills 实战:自动化工作流与技能管理
  • Linux 环境下的 Git 版本控制实战指南
  • 低空经济驱动下无人机光伏巡检技术革新
  • Kafka 核心架构与分布式存储

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online