JAVAEE值之网络原理(1)_用户数据报协议(UDP)、概念、特点、结构、代码实例

news2025/6/26 9:17:43

前言

 在前两节中我们介绍了UDP数据报套接字编程,但是并没有对UDP进行详细介绍,本节中我们将会详细介绍传输层中的UDP协议。


一、什么是UDP?

 UDP工作在传输层,用于程序之间传输数据的。数据一般包含:文件类型,视频类型,jpg图片等。

1.1 基本概念:

UDP 的全称: 用户数据报协议(UDP,User Datagram Protocol),UDP 为应用程序提供了一种无需建立连接就可以发送封装的 IP 数据包的方法。如果程序员选择的是 UD, 而不是 TCP 的话,那么该应用程序相当于就是和 IP 直接打交道的。
 从应用程序传递过来的数据,会附加上多路复用/多路分解的源和目的端口号字段,以及其他字段,然后将形成的报文传递给下一层(网络层),网络层将传输层报文段封装到 IP 数据报中,然后尽力而为的交付给目标主机。最关键的一点就是,使用 UDP 协议在将数据报传递给目标主机时,发送方和接收方的传输层实体间是没有握手的。正因为如此,UDP 被称为是无连接的协议

1.2 UDP的特点

 UDP传输的过程类似于寄信。

无连接

 知道对端的IP和端口号就直接进行传输,不需要建立连接。

不可靠

 没有任何安全机制,发送端发送数据报以后,如果因为网络故障该段无法发到对方,UDP协议层也不会给应用层返回任何错误信息;

面向数据报

 应用层交给UDP多长的报文,UDP原样发送,既不会拆分,也不会合并。比如:用UDP传输100个字节的数据:

如果发送端一次发送100个字节,那么接收端也必须一次接收100个字节;而不能循环接收10次, 每次接收10个字节。

缓冲区

UDP只有接收缓冲区,没有发送缓冲区:

  1. UDP没有真正意义上的 发送缓冲区。发送的数据会直接交给内核,由内核将数据传给网络层协议进行后续的传输动作;
  2. UDP具有接收缓冲区,但是这个接收缓冲区不能保证收到的UDP报的顺序和发送UDP报的顺序一致;如果缓冲区满了,再到达的UDP数据就会被丢弃;

大小受限

 UDP协议首部中有一个16位的最大长度。也就是说一个UDP能传输的数据最大长度是64K(包含UDP首部)

二、UDP 报文结构

 如下图所示: UDP 的报文结构,每个 UDP 报文分为 UDP 报头和 UDP 数据区两部分。报头由 4 个 16 位长(2 字节)字段组成,分别说明该报文的源端口、目的端口、报文长度和校验值
在这里插入图片描述

16位源端口号(Source Port) :

 这个字段占据 UDP 报文头的前 16 位,通常包含发送数据报的应用程序所使用的 UDP 端口。接收端的应用程序利用这个字段的值作为发送响应的目的地址。这个字段是可选项,有时不会设置源端口号。没有源端口号就默认为 0 ,通常用于不需要返回消息的通信中。

16位目标端口号(Destination Port)

表示接收端端口,字段长为 16 位。

长度

 该字段占据 16 位,表示 UDP 数据报长度,包含 UDP 报文头和 UDP 数据长度。因为 UDP 报文头长度是 8 个字节,所以这个值最小为 8,最大长度为 65535 字节。

16位校验和(Checksum)

 UDP 使用校验和来保证数据安全性,UDP 的校验和也提供了差错检测功能,差错检测用于校验报文段从源到目标主机的过程中,数据的完整性是否发生了改变。常见的检验方法:循环冗余检测(CRC)。

  • 为什么 UDP 会提供差错检测的功能?
     这其实是一种 端到端 的设计原则,这个原则说的是要让传输中各种错误发生的概率降低到一个可以接受的水平。
  • 如何基于校验和来完成数据校验呢?
  1. 发送方,把要发送的数据整理好(称为 data1),通过一定的算法,计算出校验和 checksum1
  2. 发送方把 data1 和 checksum1 一起通过网络发送出去.
  3. 接收方收到数据, 收到的数据称为 data2(数据可能和 data1 就不一样了),收到数据cHecksum1
  4. 接收方再根据 data2 重新计算校验和 (按照相同的算法),得到 checksum2
  5. 对比 checksum1 和 checksum2 是否相同,如果不同, 则认为 data2 和 data1 一定不相同.如果checksum1 和 checksum2 相同,则认为 data1 和 data2 大概率是相同的(理论上存在不同的可能性,概率比较低,工程上忽略不计)

三、通过代码理解UDP的特点

3.1 无连接

UDP协议本身不会储存对端的信息,要在发送数据的时候,才会显示指定要传输给谁?

 DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),response.getBytes().length,
 				requestPacket.getSocketAddress()); 
 			// 构造这个数据报,需要指定数据内容,也指定下一个数据报要发给谁
 socket.send(responsePacket);

3.2 不可靠

3.3 面向数据报

 DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),response.getBytes().length,
 				requestPacket.getSocketAddress()); 
 			// 构造这个数据报,需要指定数据内容,也指定下一个数据报要发给谁
 socket.send(responsePacket);

3.4 全双工

 通过一个socket,既可以send,也可以receive.

	socket.send(requestPacket);
  // 3.尝试服务器返回的响应了
   DatagramPacket responsePacket = new DatagramPacket(new byte[4096],4096);
   socket.receive(responsePacket);

上一节中的参考代码(https://blog.csdn.net/2301_80653026/article/details/139443856):

UDP客户端

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.nio.channels.DatagramChannel;

/**
 * @author Zhang
 * @date 2024/5/2015:38
 * @Description:
 */
public class UdpEchoServer {

    //创建一个datagramSocket对象,这是后续操作网卡的基础
    private DatagramSocket socket = null;

    public UdpEchoServer(int port) throws SocketException {
        //此写法是手动指定端口
        socket = new DatagramSocket(port);

        // 此写法是让服务器自动分配端口
       // socket = new DatagramSocket();

    }

    //通过这个方法来启动服务器
    public void start() throws IOException {
        System.out.println("服务器启动");

        while(true){
            // 1. 读取请求并解析
            /**
             *  DatagramPacket这个队形来承载从网卡这边读取的数据,
             *  收到的数据需要一个内存空间来保存这个数据
             *  DatagramPacket 内部不能自动分配空间,需要程序员手动创建,交给DatagramPacket进行处理
             */
            DatagramPacket requestPacket  = new DatagramPacket(new byte[4096],4096);
            socket.receive(requestPacket);   //当服务器一旦启动,就会立即执行receive方法,入伏哦客户端请求还没到,receive就会阻塞到客户端请求到达
            // 当完成receive后,数据以二进制的形式存储到DatagramPacket
            // 要想把这里的数据显示出来,好需要把这个二进制转变成字符串
            String request = new String(requestPacket.getData(),0,requestPacket.getLength());

            // 2.根据请求计算响应(一般服务器都会经理的过程)
            // 由于此处是回显服务器,请求是啥样,响应就是啥样
            String response = process(request);

            // 3. 把响应写会到客户端
            //      写一个响应对象,DatagramPacket
            //      往DatagramPacket 构造刚才数据,并通过 sent 返回

            DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),response.getBytes().length,requestPacket.getSocketAddress());
            // 构造这个数据报,需要指定数据内容,也指定下一个数据报要发给谁
            socket.send(responsePacket);

            // 4.打印一个日志,把这次数据交互的详情打印出来
            System.out.printf("[%s:%d] req = %s, resp = %s\n",requestPacket.getAddress().toString(),
                    requestPacket.getPort(),request,response);
        }
    }

    public String process(String request){
        return request;
    }
    public static void main(String[] args) throws IOException {
        UdpEchoServer server = new UdpEchoServer(9090);
        server.start();
    }
}
服务端

import java.io.IOException;
import java.net.*;
import java.util.Scanner;

/**
 * @author Zhang
 * @date 2024/5/2015:38
 * @Description:
 */
public class UdpEchoClient {

    private DatagramSocket socket = null;
    private  String serverIP = "";
    private  int serverPort = 0;

    public  UdpEchoClient(String ip,int port) throws SocketException {
        // 创建这个对象,不能手动指定端口
      socket = new DatagramSocket();
      //由于UDP自身不会持有对端的信息,就需要在应用程序里,吧对端的情况给记录下来
        serverIP = ip;
        serverPort = port;
    }

    public void start() throws IOException {
        System.out.println("客户端启动!");
        Scanner scanner = new Scanner(System.in);
        while (true){
            // 1.从控制台读取数据,作为请求
            System.out.print("->");
            String request = scanner.next();
            // 2. 把请求内容构造成 DatagramPacket 对象,发送给服务器
            DatagramPacket  requestPacket = new DatagramPacket(request.getBytes(), request.getBytes().length,
                    InetAddress.getByName(serverIP), serverPort);
            socket.send(requestPacket);

            // 3.尝试服务器返回的响应了
            DatagramPacket responsePacket = new DatagramPacket(new byte[4096],4096);
            socket.receive(responsePacket);
            // 4.把响应转换成字符串,并先显示出来
            String response =  new String(responsePacket.getData(),0,responsePacket.getLength());
            System.out.println(response);
        }
    }

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

总结

UDP特点:无连接、不可靠、面向数据报、全双工。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1822813.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringCloud2023 - 学习笔记

文章目录 1. 简介1.1 基础知识1.2 组件更替与升级 2. 微服务基础项目构建2.1 创建项目2.2 Mapper4生成代码2.3 支付模块编码2.4 项目完善2.5 订单模块编码2.6 工程重构 3. consul服务注册与发现3.1 consul简介3.2 consul下载安装3.3 微服务入驻3.4 order订单微服务入驻3.5 其他…

美摄科技匿名化处理解决方案,包含模糊、同色、马赛克、效果遮挡等各种形式

信息安全已成为企业发展中不可忽视的重要一环,随着信息安全法规的日益严格和公众对个人隐私保护意识的不断提高,企业如何在保障业务顺畅进行的同时,满足信息安全和隐私保护的要求,成为了亟待解决的问题。美摄科技凭借其强大的技术…

手把手搭建 Nginx + VIP + Keepalived 高可用集群

文章目录 1、前置讲解1.1、常用方案1.2、实现流程 2、集群搭建2.1、环境准备2.2、关于 Nginx2.2.1、安装 Nginx2.2.2、调整 Nginx 首页 2.3、关于 Keepalived2.3.1、安装 Keepalived2.3.2、编写 Shell2.3.3、调整 KeepAlived 配置 1、前置讲解 其实阿里云ECS本身不支持使用服务…

Kubernetes集群持久化部署实践

WordPress 网站持久化部署 要持久化MariaDB 可以把 Deployment 改成了 StatefulSet,修改 YAML添加“serviceName”“volumeClaimTemplates”这两个字段,定义网络标识和 NFS 动态存储卷,然后在容器部分用“volumeMounts”挂载到容器里的数据目…

一文搞懂阻塞赋值和非阻塞赋值

目录 2.非阻塞赋值举例3.阻塞赋值举例4.总结 微信公众号获取更多FPGA相关源码: # 1.阻塞赋值和非阻塞赋值的区别: (1)阻塞赋值"",必须是阻塞赋值完成后,才进行下一条语句的执行;赋值一旦完成,等号…

docker环境中配置phpstorm php xdebug调试工具

本文介绍通过docker compose的使用方式 第一步:在php镜像中安装phpxdebug扩展,比如php7.4对应的是xdebug3.1.6 第二步:设置项目中的docker-compose.yml docker-compose 增加开启xdebug的环境变量,host.docker.internal是宿主机的地址&#…

MBTI:探索你的性格类型

人不走空 🌈个人主页:人不走空 💖系列专栏:算法专题 ⏰诗词歌赋:斯是陋室,惟吾德馨 目录 🌈个人主页:人不走空 💖系列专栏:算法专题 ⏰诗词歌…

4.音视频 AAC SSAASS

目录 AAC 1.什么是ADIF和ADTS? 2.ADTS的数据结构是怎样的? SSA/ASS 1.SSA/ASS的基本结构 AAC AAC(Advanced Audio Coding,高级音频编码)是一种声音数据的文件压缩格式。AAC分为ADIF和ADTS两种文件格式。 1.什么是ADIF和ADTS&#xff…

Day01 C语言嵌入式

目录 1、嵌入式知识体系 2、计算机的组成原理 3、计算机之父 4、C语言标准 5、关键字 6、字符编码 7、字符集 1、嵌入式知识体系 备注:图片来源于网络,为嵌入式知识体系思维导图,分为软件、硬件和理论知识三个部分,仅供各位…

【LeetCode】4,寻找两个正序数组中的中位数

题目地址 B站那个官方解答视频实在看不懂,我就根据他那个代码和自己的理解写一篇文章 1. 基本思路 在只有一个有序数组的时候,中位数把数组分割成两个部分。中位数的定义:中位数,又称中点数,中值。中位数是按顺序排列…

全志摄像头屏幕预览、录制(H264)

一、录像 使用dvr_test录制视频 运行dvr_test demo出现space not enought问题,修改/etc/dvrconfig.ini文件下对应的camera节点下cur_filedir属性无效 修改以下内容解决; 录制时出现摄像头画面异常,如下 摄像头型号与打印信息匹配: 但是出现画…

整蛊软件/插件使用方法与配置步骤~

今天出一期整蛊软件的使用方法与配置步骤 很多人在使用整蛊软件的时候 想自己添加更多的玩法内容 但是还不知道如何去配置 这期给大家出一下图文教程步骤 基本上也是软件的功能介绍使用方式~ 案例可扫码查看 第一步:打开软件输入卡密登录: 卡密费用&…

最好用的邮箱管理软件推荐,邮箱管理软件哪个好?(干货篇)

在快节奏的工作与生活中,有效管理电子邮件成为提升个人与团队效率的关键。 面对海量信息流,一款好的邮箱管理软件不仅能够帮助我们高效地整理收件箱,还能确保重要邮件不会错过,同时提升通讯的便捷性和安全性。 本文将为您推荐几款…

AUTOSAR平台中的信息安全标准模块

面向MCU端的AUTOSAR CP平台加密组件——Crypto ECU中所有的软件单元都遭受到信息安全攻击的可能。AUTOSAR为保障ECU信息和数据安全,定义了CRYPTO 组件,包含 SecOC、KeyM、IdsM、Csm、CryIf 和Crypto Driver 等标准模块。CRYPTO组件提供各种加解密算法以及密钥管理功…

另辟蹊径的终端防病毒

在数字时代的浪潮中,网络安全问题愈发凸显,防病毒成为了保护信息安全的重要一环。而白名单作为一种有效的安全策略,在防病毒方面发挥着不可或缺的作用。 首先,我们需要明确白名单的概念。白名单是一种管理和安全实践,用…

掌握这招,串口通信高频收发32W数据,0丢包!

我做过挺多串口通讯类的产品,有用485通讯的pdu,有wifi/4G/蓝牙通讯类的网关... 做串口的应用,把串口外设调通只是第一步,串口只是数据传输的媒介,在此基础上,两个设备/器件要进行通信,传递更有意…

软件使用教程

昨天分享了一款专业软件,但是大家不知道怎么pj,好多小伙伴被文件夹下面的说明带跑偏了,所以今天特地发个文说一下科学使用的过程,需要软件的可以看昨天的文章! 话不多说那好小板凳,教程开始了 1、第一步&…

18. 四数之和 - 力扣

1. 题目 给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复): 0 …

空间搜索geohash概述;redis的geo命令

概述 通常在一些2C业务场景中会根据用户的位置来搜索一些内容。通常提供位置搜索的都是直接通过redis/mongodb/es等中间件实现的。 但是这些中间件又是怎么实现位置搜索的呢; 查了一番资料,发现背后一个公共的算法Geohash。 搜索的时候可以根据距离对…

认识Redis 主从同步、事务和Memcached的区别

08- 什么是 Redis 主从同步? Redis 的主从同步(replication)机制,允许 Slave 从 Master 那里,通过网络传输拷贝到完整的数据备份,从而达到主从机制。 主数据库可以进行读写操作,当发生写操作的时候自动将数据同步到从…