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

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

时间:2024-06-13 22:31:22浏览次数:28  
标签:UDP DatagramPacket socket responsePacket JAVAEE 实例 new 数据

前言

 在前两节中我们介绍了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特点:无连接、不可靠、面向数据报、全双工。

标签:UDP,DatagramPacket,socket,responsePacket,JAVAEE,实例,new,数据
From: https://blog.csdn.net/2301_80653026/article/details/139604704

相关文章

  • OCP-042之:Oracle实例管理
    2.Oracle实例管理2.1Instance管理Oracle实例(instance)是一组Oracle后台进程和内存结构的集合。后台进程主要包括SMON,PMON,DBWR,CKPT和LGWR等;内存结构包括数据库高速缓冲区、重做日志缓冲区、共享池、大池等组成系统全局区(SGA)的重要组件。实例主要实现对数据库的访......
  • HTML实例网页代码, 本实例适合于初学HTML的同学 (个人博客网站)
    ......
  • Java学习 - MySQL数据增删更清操作 实例
    INSERTINTO-插入语法1-【常用;支持多行;可用于子查询】INSERTINTO表名(字段列表)VALUES(字段值列表),(字段值列表),(字段值列表),(字段值列表);注意如果想设置空值,可以用NULL表示字段列表和字段值列表必须一一对应字段列表的顺序可以和表定义顺序不同可以省略......
  • Java学习 - MySQL数据库常用命令 实例
    进入MySQL命令行>>mysql-u用户名-p>>输入密码查看MySQL的版本--方法1:通过命令行>>mysql--version>>mysql-V--方法2:通过MySql内置函数>>SELECTVERSION();查看所有的数据库SHOWDATABASES;打开指定的数据库USEtables;查看当前数据库所有的表......
  • Java学习 - MySQL数据库导入和查询方式 实例
    目录练习用数据库导入基础查询条件查询排序查练习用数据库导入下载相关资源中的myemployess.sql执行sql脚本sourcemyemployees.sql;基础查询SELECT子句SELECT查询字段FROM表名;--查询字段包括:表的字段,常量值,表达式,函数--查询的结果是一个虚拟的表查......
  • 【设计模式】创建型设计模式之工厂模式(简单工厂、工厂方法、抽象工厂、go简单实例)
    一般情况下,工厂模式分为三种更为细分的类型:简单工厂、工厂方法和抽象工厂。其中,前两者的方法原理比较简单,在实际的项目里也比较常用;而抽象工厂的原理稍微复杂,在实际的项目中相对也不常用。所以,我们今天重点是前两种工厂模式,简单工厂在下面这段代码里,我们根据配置文件的后......
  • 13. UDP协议与RTP协议
    UDP协议UDP协议比较简单:UDP的长度是固定的,用总长度-UDP长度就是数据长度。UDP是不保证他的有序性和可靠性的。对于音频和视频是这样是比较好的,因为这段丢了,我们可以从下一段在开始解码。RTPRTP协议概述RTP(Real-timeTransportProtocol)是用于Internet上针对多媒体......
  • 借助ChatGPT“从0到1”高效完成优质论文写作,4大关键步骤(技巧+实例),小白轻松上手
    最近很多朋友找我咨询ChatGPT写论文的事,说他们虽然知道GPT很厉害,但是却不知道怎么上手使用,有的是使用了但并没有那么理想,对于AI输出的结果并不满意,从零开始撰写论文似乎是一项艰巨的工作。我将通过这篇文章介绍如何借助ChatGPT从0到1一步一步完成从文献调研到论文发表的全过......
  • 数据类型与深浅拷贝理解 vs 不同语言环境下深浅拷贝实例
    一、在探讨深浅拷贝的问题之前需要先理解两种数据类型值类型数据(基本数据类型):存储在栈内存,占据固定大小的空间,直接存储其数据(值的赋值是深拷贝);引用类型数据:这种数据类型的变量通常存储在栈区,存的是指向实际数据的指针,而实际的数据是存储在堆区,访问数据通过指针去访问(值的赋值......
  • python中实例方法、类方法、静态方法
    实例方法self:代表类的实例类方法cls:代表类这个名称本身静态方法不能传递类的实例self,也不能传递类本身cls点击查看代码classMyClass:"""静态成员变量静态成员变量是被类的所有实例共享的访问方式:通过类名."""my_static_variable=0"......