网络编程(一):UDP socket api => DatagramSocket DatagramPacket

目录

1. TCP 和 UDP

1.1 TCP / UDP 的区别

1.1.1 有连接 vs 无连接

 1.1.2 可靠传输 vs 不可靠传输

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

1.1.4 全双工 vs 半双工

2. UDP socket api

2.1 DatagramSocket

2.1.1 构造方法

2.1.2 receive / send / close

2.2 DatagramPacket

2.2.1 构造方法

2.2.2 getAddress / getPort / getSocketAddress

3. UDP 回显 客服端-服务器

3.1 UDP 回显服务器

3.1.1 给服务器指定固定端口号

3.1.2 运行服务器

3.1.2.1 读取请求并解析

3.1.2.2 根据请求, 计算响应

3.1.2.3 返回响应

3.1.2.4 记录客户端/服务器的交互过程

3.2 UDP 回显客户端

3.2.1 给客户端随机分配空闲端口

3.2.2 运行客户端

3.2.2.1 用户输入请求

3.2.2.2 构造请求数据包

3.2.2.3 发送请求数据包

3.2.2.4 接收服务器响应

 3.2.2.5 解析响应数据


1. TCP 和 UDP

上文说到, 作为程序员, 我们写代码时, 主要是和应用层来打交道(应用程序).

将应用层的数据交给传输层, 就需要调用操作系统提供的一组 api(传输层向应用层提供的), 也就是 socket api.

而在传输层中有两个核心的协议:

  1. TCP 协议
  2. UDP 协议

这两个协议差别非常大, 编写代码时, 也是截然不同的风格, 于是 socket api 就提供了两套, 一套给 TCP 使用 ,一套给 UDP 使用.

1.1 TCP / UDP 的区别

  • TCP => 有连接, 可靠传输, 面向字节流, 全双工
  • UDP => 无连接, 不可靠传输, 面向数据报, 全双工

1.1.1 有连接 vs 无连接

这里的连接, 是一个抽象的概念, 指的是虚拟的/逻辑上的连接, 是指两个人之间有没有建立 "连接/联系" , 并非物理上网络的连接.

所以这里的 有/无连接, 就是指彼此之间, 有没有保存对方的信息(有没有保存对端的IP/端口). 

(物理上的连接(网线, wifi ...), 肯定是都有的, 因为要进行网络通信, 物理连接是必不可少的!!)

 比如, 两个人结婚, 去民政局领了结婚证后, 你们两个人才建立起这样的 虚拟的/逻辑的上的 连接, 你们两个人真正的 "连接" 了起来, 你是她的丈夫, 她是你的妻子.

  • 对于 TCP 来说(有连接), TCP 协议中就保存了对端的信息. A 和 B 通信, A 中就保存了 B 的信息, B 中就保存了 A 的信息(彼此之间, 知道是谁和自己建立的连接).
  • 而对于 UDP 来说(无连接), UDP 协议中就没有保存对端的信息. (但是我们可以在代码中手动使用变量来保存对端信息, 但这属于 UDP 的行为)

 1.1.2 可靠传输 vs 不可靠传输

网络通信时, 数据是很容易出现丢失的(丢包, 原本要传输的数据被修改, 被识别出来后就会被丢弃):

  1. 光/电信号, 可能会收到外界磁场的干扰导致丢包
  2. 网络是通过 路由器/交换机 来构建的, 当需要转发的数据量超过了 路由器/交换机 的转发上限时, 就会出现"堵车", 造成丢包(下载很大的资源时, 网络就会很卡)

所以, 传输的数据, 是不一定 100% 到达目的地的, (中间可能出现丢包现象):

  • 而 TCP 可靠传输 => 虽然不能保证 100% 发送成功, 但是会尽可能的提高传输成功的概率, 如果出现丢包, 就会尝试重新发送.(但是也会降低传输速率)
  • 而 UDP 不可靠传输 => 把数据发送后, 就不再管了(不管发送成功与否)~~ (传输速率同时也更快)

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

  • 面向字节流: 读取数据的时候, 以字节为单位, 一次读写一个字节的数据
  • 面向数据报: 读取数据的时候, 以一个数据报为单位(不是字符)

所以 TCP 可以支持任意长度的读取, 但是存在粘包问题.

而 UDP 一次只能读取一整个 UDP 数据报, 虽然不存在粘包问题, 但是却存在长度限制.

1.1.4 全双工 vs 半双工

  • 全双工: 一个通信链路, 支持双向通信(既能读, 也能写)
  • 半双工: 一个通信链路, 只支持单向通信(要么读, 要么写, 二选一)

2. UDP socket api

socket api 针对 TCP 和 UDP 提供了两套不同的 api , 我们先来看 UDP 的 socket api.

2.1 DatagramSocket

在之前的博客提到过, "文件" 是一个广义上的概念, 文件不止指硬盘上存储的文件, 还可以代指一些硬件设备(硬件设备被抽象成文件, 操作系统通过文件对硬件设备统一进行管理).

其中, 网卡就被抽象成 socket 文件, 我们可以通过操作 socket 文件, 间接来操作网卡.

而 DatagramSocket 就可以认为是 "网卡的遥控器", 可以通过 DatagramSocket 对象来向网卡中读写数据.

2.1.1 构造方法

操作网卡时, 由于网卡被抽象成 socket 文件, 所以操作网卡的流程和操作文件的流程是类似的:

  1. 打开文件
  2. 读写文件(读写网卡)
  3. 关闭文件

其中, DatagramSocket 通过构造方法 new 出对象后, 就相当于打开文件成功.

DatagramSocket 构造方法有两种:

  1. 无参版本 => 随机分配一个未被使用的端口号
  2. 带带参版本 => 指定一个固定的端口号

(使用 socket 时, 会关联上一个端口号, 以此区分主机上不同的应用程序)

我们可以把 DatagramSocket 理解为一个包裹,

  • 里面的物品就是要传输的数据(UDP 数据包)
  • 而端口号就是收货人(我)的电话, 快递小哥可以根据电话来确定唯一的收货人是谁.(端口号能定位到这个主机中的某个进程,从而实现交互)

2.1.2 receive / send / close

  • receive --- 从 socket 文件(网卡)中读取 UDP 数据包. 

当有人向这里发送数据包后, receive 可以从网卡中将数据包读出来, 填充到 DatagramPacket 对象中(输出型参数中). 也就是说, 接受数据前(调用前), 需要先构造一个空的 DatagramPacket(非null, 只是未初始化).

  • send --- 发送 UDP 数据包. 前提是, 有目的 IP 和 目的端口
  • close --- 关闭 socket 文件

2.2 DatagramPacket

DatagramPacket 用来表示一个完成的 UDP 数据包, 数据包的载荷使用 字节数组(byte[]) 来存储.

2.2.1 构造方法

UDP 数据包的载荷数据(字节数组), 需要通过构造方法来指定:

2.2.2 getAddress / getPort / getSocketAddress

  • getAddress => 得到源 IP
  • getPort => 得到源端口
  • getSocketAddress => 得到源 IP 和 源端口, 封装在一个 InetAddress 对象中

上面说到 DatagramSocket 可以理解为一个快递包裹

而 DatagramPacket 就是包裹中的物品, 也就是要传输的数据


3. UDP 回显 客服端-服务器

这里通过模拟回显客户端服务器来加强对 DatagramSocket DatagramPacket 的理解和使用.

所谓回显, 就是指 客户端的请求是啥, 服务器的相应就是啥.(请求和相应是一样的).

3.1 UDP 回显服务器

对于服务器来说, 应该有一个固定的端口号(用户可以根据需求, 精准的找到某个服务器),

3.1.1 给服务器指定固定端口号

构造 DatagramSocket 对象, 读写网卡中的数据, 并使用带参版本的构造方法给服务器指定固定的端口号:

3.1.2 运行服务器

第二步就是把服务器运行起来, 但是对于服务器来说, 是不知道用户什么时候来访问的, 所以要 7*24 小时的运行 => while(true).

一个服务器程序, 通常都有以下三点大的流程:

  1. 读取请求并解析
  2. 根据请求, 计算响应
  3. 把响应返回给客户端
3.1.2.1 读取请求并解析

使用 socket 的 receive 方法来读取用户发来的请求(一个 DatagramPacket 数据包), 这里需要注意的是, receive 使用 "输出型参数", 将读取到的数据填充到 DatagramPacket 对象中.

具体步骤如下:

  1. 构造 DatagramPacket 对象(报头 + 载荷), new 字节数组作为 UDP 数据包的载荷(报头我们不需考虑, DatagramPacket 对象底层已经实现). 
  2. 调用 receive 方法读取请求, 填充到 DatagramPacket 对象中
  3. 将读取到的 UDP 载荷(字节数组, 二进制信息)取出来, 构造出一个 String 信息 (1. getdata 拿到字节数组 2. requestPacket.getLength 拿到数组有效信息的长度 3. 根据以上信息, new String() 构造字符串)

3.1.2.2 根据请求, 计算响应

根据请求, 计算响应. 这一步骤是服务器中最关键的步骤, 但是由于我们这里构造是回显服务器, 所以 请求内容就是响应内容.

3.1.2.3 返回响应

由于 UDP 协议本身是没有保存对端的信息的(没有保存目的IP/目的端口), 而返回响应的前提是明确 数据包要给谁发, 发到哪, 即在构造数据包时, 要指定好目的IP和目的端口.

首先, 根据响应的字符串(response)构造出 UDP 响应数据包(responsePacket).

构造相应数据包 responsePacket 的过程如下:

  1. 拿到字符串底层的字节数组(字符串底层就是通过字节数组(byte[] value)存储数据) => response.getBytes()
  2. 拿到字节数组的长度 => response.getBytes().length(); 注意:这里拿的必须是字节数组的长度, 而不是字符串的长度(字符 != 字节)
  3. 通过 DatagramPacket 的构造方法, 构造 UDP响应数据包.
  4. 响应数据包的目的IP和目的端口, 就是请求的源IP和源端口. 可以从 receive 得到的 请求数据包中得到源IP/源端口(requestPacket.getgetSocketAddress()).

注意:

请求数据包(requestPacket)作为输出型参数, 经过 receive 的接收填满数据后, 其 UDP 报头中包含了 源端口/目的端口, IP报头中包含了 源IP/目的IP. (虽然说 requestPacket 是一个 UDP 数据包, 但是 IP信息也是包含的)

构造完成 响应数据包(responsePacket)后, 调用 send 方法给客户端返回 响应.

3.1.2.4 记录客户端/服务器的交互过程

打印日志信息:

注意事项:

  • socket 文件需要调用 close 方法来关闭吗?

答: 文件是否要关闭, 需要考虑文件对象的生命周期是怎样的. 虽然 socket 是一个文件资源, 但是它是不需要 close 的, 因为此处的 socket 会自始至终伴随整个 UDP 服务器(如果关闭文件, 那么服务器就不能使用了), 所以只有当服务器关闭后(进程关闭), 文件资源才可以关闭, 而进程关闭, 就会自动释放 PCB 文件描述符表中的所有资源, 也就不需要手动 close.

  • 当 receive 没有接收到客户端的请求时, 服务器会忙等吗??

: 不会. 当 receive 没有从网卡中读到请求时, receive 是会触发阻塞等待的. 当有请求发来时, receive 才会继续往下执行.

  • 客户端给服务器发的数据, 就是字符串. 本身收到的 DatagramPacket 的二进制数据就是从 String 转来的, 我们在服务器上只是再把 二进制数据 转回 String.
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;/*** Created with IntelliJ IDEA.* Description: 服务器端* User: dings* Date: 2024-11-03* Time: 14:33*//*** 回显服务器端*/
public class UdpEchoServer {private DatagramSocket socket = null;public UdpEchoServer(int port) throws SocketException {// 服务器端 => 固定端口号// socket 对象可以看做一个包裹, 其接受/发送的数据就是包裹中的物品// 端口号就相当于我的手机号, 快递小哥能准确的将收货人定位到我socket = new DatagramSocket(port);}public void start() throws IOException {System.out.println("服务器启动!");while (true) {// 1. 接收数据// Packet对象相当于一个完整的 UDP 数据包// 这里的字节数组, 就是 UDP 载荷DatagramPacket requestPacket = new DatagramPacket(new byte[4096], 4096);// requestPacket 作为 "输出型参数"// 从 socket 中读取请求, socket 可以看做一个包裹, 其中的物品就是数据socket.receive(requestPacket);// 将字节数组(读到的二进制数据), 转化为字符串, 只是转化其中的有效信息(getLength)String request = new String(requestPacket.getData(), 0, requestPacket.getLength());// 2. 根据请求, 计算相应(服务器最关键的一步)// 这里是回显服务器, 直接返回请求即可String response = process(request);// 3. 返回相应// 把构造好的数据包发送出去, 前提是数据包中包含了目的IP和目的端口// 不能直接发送. UDP 协调没有保存对端信息(目的IP和目的端口), 需要根据请求来得到目的IP和目的端口// 而响应的目的IP和目的端口, 就是请求的源IP和源端口// (构造方法传入的是目的IP和目的端口) (getAddress/getPort/getSocketAddress => 得到的是源IP/源端口)DatagramPacket responsePacket = new DatagramPacket(response.getBytes(), response.getBytes().length, requestPacket.getSocketAddress());socket.send(requestPacket);// 4. 打印日志信息System.out.printf("[%s %d], request : %s, response : %s\n", requestPacket.getAddress().toString(), requestPacket.getPort(), request, response);}}/*** 根据请求, 计算相应* @param request* @return*/private String process(String request) {return request;}public static void main(String[] args) throws IOException {UdpEchoServer server = new UdpEchoServer(9090);server.start();}
}

3.2 UDP 回显客户端

3.2.1 给客户端随机分配空闲端口

对于客户端来说, 需要明确以下两点:

  1. 客户端是不能指定固定端口的(由操作系统随机分配一个空闲的端口)!!
  2. 在客户端中, 要明确所访问的服务器的IP和端口(指定目的IP/目的端口)!!

如果客户端指定的是固定端口, 那这个端口很可能已经被电脑上的其他程序给占用了(造成冲突), 运行时就会使客户端运行失败!! 而默认分配空闲端口, 就可以避免这种情况.

而为什么服务器可以指定固定端口呢??

  • 因为服务器就是一个服务网站, 它必须是固定的, 不能变来变去, 要不然用户就找不到了!!
  • 而且服务器是在程序员手中的, 即使出现端口冲突, 程序员也可以很快处理.
  • 而客户端是在用户手中的, 程序员是无法控制用户的电脑的~

举个例子:

汤老湿在陕科大食堂18号卖东北熏肉大饼(IP: 陕科大食堂, 端口: 18号)

此时, 老湿的档口就是服务器, 而来买饼的学生就是客户端.

显而易见, 老湿的档口(服务器端口号)是不能变来变去的, 他卖饼就是在18号档口卖的, 不能今天一个地明天一个地, 这样学生就找不着了~~

而来买饼的学生(客户端), 买完饼后, 肯定也不是固定在一个座位上吃饼, 因为这是食堂, 很可能昨天的坐的位置已经被其他人占了(客户端端口冲突), 所以只能坐在一个没有人的位置上吃饼(空闲端口).

3.2.2 运行客户端

3.2.2.1 用户输入请求

从控制台读取用户请求:

3.2.2.2 构造请求数据包

注意: 请求是要发送给服务器的, 所以要在数据包中指定服务器的IP和端口.

(请求数据包 = 载荷(字节数组) + 目的IP/目的端口)

因为 serverIP 是字符串, 所以要通过 InetAddress.getByName 构造一个 IP 地址(目的IP).

3.2.2.3 发送请求数据包

调用 socket 的 send 方法, 发送 UDP 请求数据包:

3.2.2.4 接收服务器响应

发送请求后, 客户端会收到服务器的响应, 仍然需要构造一个空的数据包作为输出型参数, 填充 receive 读到的响应数据.

 3.2.2.5 解析响应数据

最终, 运行客户端程序:

注意: "127.0.0.1" 是一个特殊的 IP(环回 IP), 表示当前主机(不管主机实际IP是啥, 都表示当前主机), 类似于 this.

由于此时我们写的 回显客户端-服务器, 是在同一台主机上的, 就可以使用 127.0.0.1 来访问.

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.Scanner;/*** Created with IntelliJ IDEA.* Description: 客户端* User: dings* Date: 2024-11-04* Time: 8:03*//*** 回显 客户端*/
public class UdpEchoClient {private String serverIP;// 服务器IPprivate int serverPort;// 服务器端口号private DatagramSocket socket = null;public UdpEchoClient(String serverIP, int serverPort) throws SocketException {// 操作系统随机指定一个空闲的端口号socket = new DatagramSocket();// 指定访问的服务器的地址this.serverIP = serverIP;this.serverPort = serverPort;}public void start() throws IOException {Scanner scanner = new Scanner(System.in);while (true) {// 1. 从控制台读取用户请求System.out.println("请输入你的请求: ");if(!scanner.hasNext()) {break;}String request = scanner.next();// 2. 构造请求数据包(载荷(字节数组) + 目的IP/目的端口)// 后续会将请求数据包发送给服务器端, 所以, 请求数据包要指定服务器地址(目的IP/目的端口)DatagramPacket requestPacket = new DatagramPacket(request.getBytes(), request.getBytes().length, InetAddress.getByName(serverIP), serverPort);// 3. 发送 请求数据包socket.send(requestPacket);// 4. 接收服务器返回的响应// responsePacket 作为输出型参数, 填充服务器返回的响应DatagramPacket responsePacket = new DatagramPacket(new byte[4090], 4090);socket.receive(responsePacket);// 5. 解析响应信息// 将响应中的二进制数据(字节数组)转化为字符串, 只转化其中的有效数据(getLength)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();}
}

END

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

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

相关文章

JDBC入门

什么是JDBC JDBC(Java DataBase Connectivity)就是Java数据库连接,说白了就是用Java语言来操作数据库。原来我们操作数据库是在控制台使用SQL语句来操作数据库,JDBC是用Java语言向数据库发送SQL语句。 使用JDBC 使用JDBC会用到它…

ReactPress:深入解析技术方案设计与源码

ReactPress Github项目地址:https://github.com/fecommunity/reactpress 欢迎提出宝贵的建议,欢迎一起共建,感谢Star。 ReactPress是一个基于React框架开发的开源发布平台,它不仅仅是一个简单的博客系统,更是一个功能全…

Linux挖矿病毒(kswapd0进程使cpu爆满)

一、摘要 事情起因:有台测试服务器很久没用了,突然监控到CPU飙到了95以上,并且阿里云服务器厂商还发送了通知消息,【阿里云】尊敬的xxh: 经检测您的阿里云服务(ECS实例)i-xxx存在挖矿活动。因此很明确服务器中挖矿病毒…

Stable Diffusion LoRA, LyCoris

本节内容,给大家带来的是stable diffusion的LoRA与LyCoris模型课程。我们在上节课程中,已经详细讲解了关于大模型的使用。在stable diffusion中打造一个大模型,需要基于大量特定特征的图像集进行训练,我们通常将这个过程称之为Dre…

[RoarCTF 2019]Easy Calc 1

[RoarCTF 2019]Easy Calc 1 审题 题目就是一个计算器。 看到源代码有 calc.php 进入看到waf的源代码 知识点 RCE 解题 审核代码 <?php error_reporting(0); if(!isset($_GET[num])){show_source(__FILE__); }else{$str $_GET[num];$blacklist [ , \t, \r, \n,\, &q…

文本转SQL(Text-to-SQL),场景介绍与 Spring AI 实现

在众多的 AI 大模型的应用场景中&#xff0c;Text-to-SQL&#xff0c;也就是文本转 SQL&#xff0c;是其中实用性很高的一个。Text-to-SQL 充分利用了大模型的优势&#xff0c;把用户提供的自然语言描述转换成 SQL 语句&#xff0c;还可以执行生成的 SQL 语句&#xff0c;再把查…

Oracle 23AI创建示例库

一、示例库介绍 多年来&#xff0c;Oracle 一直使用简单的数据库模式 SCOTT 及其两个突出的表 EMP 和 DEPT&#xff0c;用于文档和培训中的各种示例。但不少小伙伴并不知道如何创建这些示例数据&#xff0c;其实Oracle官方上就有提供对应的方法&#xff0c;本文就带领大家完成…

默认 iOS 设置使已锁定的 iPhone 容易受到攻击

苹果威胁研究的八个要点 苹果手机间谍软件问题日益严重 了解 Apple 苹果的设备和服务器基础模型发布 尽管人们普遍认为锁定的 iPhone 是安全的&#xff0c;但 iOS 中的默认设置可能会让用户面临严重的隐私和安全风险。 安全研究员 Lambros 通过Pen Test Partners透露&#…

微博舆情分析:使用Python进行深度解析

目录 一、准备工作 二、基础理论知识 三、步骤详解 数据预处理 情感分析 关键词提取 四、案例分享 数据爬取 数据分析 五、优化 六、结论 在当今信息爆炸的时代&#xff0c;社交媒体平台如微博已成为公众表达意见和情感的重要渠道。微博舆情分析通过对大量微博数据进…

Unet++改进3:添加NAMAttention注意力机制

本文内容:添加NAMAttention注意力机制 目录 论文简介 1.步骤一 2.步骤二 3.步骤三 4.步骤四 论文简介 识别不太显著的特征是模型压缩的关键。然而,它在革命性的注意机制中尚未得到研究。在这项工作中,我们提出了一种新的基于归一化的注意力模块(NAM),它抑制了较不显著…

潮玩宇宙方块兽系统开发:可定制UI与多种游戏内嵌助力个性化体验

潮玩宇宙方块兽系统开发正在推动潮玩与游戏的融合&#xff0c;通过个性化的UI设计和多游戏内嵌模式&#xff0c;为用户带来了独一无二的体验。本文将从可定制UI、多游戏内嵌功能以及系统实现等方面入手&#xff0c;探讨如何构建一个极具吸引力的潮玩宇宙方块兽系统。 一、可定制…

利用亚马逊AWS IoT核心和MQTT进行数据采集的综合指南

论文标题&#xff1a;A Comprehensive Guide on Data Acquisition Utilizing Amazon AWS IOT Core and MQTT 中文标题&#xff1a;利用亚马逊AWS IoT核心和MQTT进行数据采集的综合指南 作者信息&#xff1a; Tanishq. I. KohliPradip R. Selokar 两位作者均来自印度那格浦尔…

高校宿舍信息管理系统小程序

作者主页&#xff1a;编程千纸鹤 作者简介&#xff1a;Java领域优质创作者、CSDN博客专家 、CSDN内容合伙人、掘金特邀作者、阿里云博客专家、51CTO特邀作者、多年架构师设计经验、多年校企合作经验&#xff0c;被多个学校常年聘为校外企业导师&#xff0c;指导学生毕业设计并参…

一篇文章入门docker!

文章目录 DockerUbuntu 下 docker 安装安装docker运行docker Docker的常用命令帮助命令镜像命令容器命令其他常用命令小结 分层理解一、Docker镜像的分层结构二、UnionFS与镜像分层三、镜像层的具体内容四、镜像分层的好处五、容器层与镜像层的关系 如何提交一个自己的镜像 Doc…

自动驾驶革命:从特斯拉到百度,谁将主宰未来交通?

内容概要 自动驾驶技术正在经历一个前所未有的革命性变化&#xff0c;各大企业纷纷抢占这一充满潜力的新市场。以特斯拉和百度为代表的行业巨头&#xff0c;正利用各自的优势在这一技术的赛道上展开激烈竞争。特斯拉凭借其在电动汽车和自动驾驶领域的前瞻性设计与不断革新的技…

配置管理,雪崩问题分析,sentinel的使用

目录 配置管理一&#xff1a;什么是配置管理二&#xff1a;配置共享三&#xff1a;配置热更新 雪崩问题一&#xff1a;原因分析二&#xff1a;解决方案 Sentinel一&#xff1a;快速入门二&#xff1a;请求限流三&#xff1a;线程隔离四&#xff1a;fallback五&#xff1a;服务熔…

MATLAB中,clear的使用方法

在MATLAB中,clear 命令是一个非常重要的工具,用于管理工作空间中的变量。其主要功能是清除变量,以帮助用户保持环境的整洁并避免潜在的命名冲突。以下是 clear 命令的详细使用方法和相关信息。 1. 基本用法 清除所有变量:clear此命令会清除当前工作空间中的所有变量。这意味…

前端开发实现自定义勾选/自定义样式,可复选,可取消勾选

基于后端返回数组实现多选、复选 以下代码基于vue2&#xff0c;如果有需要React/Vue3或者其他框架代码的&#xff0c;可以通过国内直连GPT4o进行代码转换&#xff0c;转换正确率99% 前端代码如下(直接拷贝到你的vue代码即可)&#xff1a; <!-- CustomCheckboxList.vue --&g…

面向对象技术简述(含设计模式)

6.9.2 面向对象技术 面向对象 对象 分类 继承 通过消息的通信 面向对象 对象 分类 继承 通过消息的通信 面向对象对象分类继承通过消息的通信其中包括&#xff1a; 对象 运行的实体&#xff1b;既包含属性/数据&#xff0c;又包含方法/行为/操作数据的函数&#xff1b;…

【RabbitMQ】04-发送者可靠性

1. 生产者重试机制 spring:rabbitmq:connection-timeout: 1s # 设置MQ的连接超时时间template:retry:enabled: true # 开启超时重试机制initial-interval: 1000ms # 失败后的初始等待时间multiplier: 1 # 失败后下次的等待时长倍数&#xff0c;下次等待时长 initial-interval…