传输层 --- UDP

news2024/10/7 19:21:25

目录

1. 传输层是什么呢?

2. 再谈端口号

2.1. 端口号是什么 

2.2. 协议号是什么 

2.3. 认识知名端口号

2.4. 端口号的相关问题

2.4.1. 一个进程可以绑定多个端口号吗?

2.4.2. 一个端口号可以被多个进程绑定吗?

2.4.3. 为什么不使用PID来标识一个进程呢

2.5. netstat 命令

2.6. pidof 命令

3. 前置性认识

4. UDP 协议

4.1. UDP的基础认识

4.2. 理解UDP报文本身

4.3. UDP字段

4.4. UDP相关特性

4.5. UDP的缓冲区

4.6. 全双工 vs 半双工

4.7. UDP 使用注意事项 

4.8. 基于UDP的应用层协议 


1. 传输层是什么呢?

传输层是计算机网络中的一种网络协议层,位于网络层和应用层之间。

它的主要作用是将应用层的数据从发送端传输给服务端,确保数据在源主机和目标主机之间可靠地传输。

2. 再谈端口号

2.1. 端口号是什么 

端口号是一个16位整数 (0 --- 65535),用于标识网络通信中的特定进程或服务的。在TCP/IP协议中,每个端口号都与一个特定的网络服务或进程相关联。端口号的作用是在主机上区分不同的网络服务和进程,使得数据能够正确地路由到目标进程。

在 TCP/IP 协议中, 用 "源IP","源端口号","目的IP","目的端口号","协议号",这样的一个五元组来标识一个通信, 在 Linux 中可以用 netstat 命令查看这个五元组。

2.2. 协议号是什么 

协议号,通常指在网络协议栈中用于标识不同网络层之间协议的数字。

在传输层,特别是在IP协议(网络层)的上下文中,协议号用来标识上一层(即传输层)的具体协议类型,以便正确地处理和转发数据包。

在IP头部中,存在一个字段专门用于指示传输层的协议类型,这就是所谓的 "协议号"。这个字段告诉IP层数据包应该如何进一步处理,即数据包应该交给哪种传输层协议(如TCP、UDP或其他协议)进行处理。例如:

  • TCP 的协议号是 6。这意味着当IP层接收到一个数据包,如果看到协议号是6,它就知道这个数据包应该交给TCP协议处理。
  • UDP 的协议号是 17。同样地,IP层收到协议号为17的数据包,就会将其转发给UDP协议处理。

总的来说,协议号是网络协议栈中用于标识和区分不同传输层协议的机制,即服务端和客户端采用什么传输层协议进行通信的,它是确保数据包能够被正确处理和传输的关键。

2.3. 认识知名端口号

由于端口号是一个16位的整数, 故它的范围是0 到 65535,通常情况下, 端口号可以分为两类:

  1. 系统端口系统端口是预留给一些常用的网络服务的端口号,范围从0到1023。例如,HTTP服务默认使用端口号80,HTTPS服务默认使用端口号443,FTP服务默认使用端口号21,等等。这些端口号被广泛应用于各种网络服务,并且通常由操作系统或网络协议栈预先分配。

  2. 动态端口动态端口是指那些未被预先分配给特定服务的端口号,范围从1024到65535。这些端口号通常由客户端在需要与服务器建立连接时动态地分配使用。例如,当你使用Web浏览器访问一个网站时,操作系统会随机选择一个未被占用的动态端口号,并将其用于与Web服务器建立连接,因此我们以前在写套接字时, 客户端不需要显式的bind端口,操作系统在特定时机会自动给客户端bind端口号。

在 Linux 操作系统中,通常有一个特定的文件用来记录特定网络服务所使用的默认端口号,这个文件通常位于 /etc/services 路径下。

cat /etc/services

用户在实现自己的网络服务时,尽量避免使用0到1023范围内的端口号,因为这些端口号通常被系统或常见的网络服务占用。如果你的应用程序尝试绑定这些端口号,可能会引发权限问题或与系统服务冲突。

一般都使用1024到65535的端口,不会与系统服务发生冲突。

2.4. 端口号的相关问题

2.4.1. 一个进程可以绑定多个端口号吗?

可以, 端口号是用于标识网络通信中的特定进程或服务的,一个端口号标识一个进程,但并不是说,一个进程只能绑定一个端口号。

例如:一个Web服务器进程可能会同时监听80端口和443端口,分别提供HTTP和HTTPS服务。

2.4.2. 一个端口号可以被多个进程绑定吗?

不可以, 由于端口号是用来标识网络通信中的一个进程, 如果一个端口号被多个进程绑定, 那么这个端口号就无法标识唯一的一个进程,从而引发冲突。因此,一个端口号不可以被多个进程绑定,否则会造成端口冲突,影响通信的正常进行。

2.4.3. 为什么不使用PID来标识一个进程呢

我们以前不是学习过PID吗,PID作为进程的标识符,也是标识一个唯一的进程啊, 为什么网络模块还要自己在搞一个端口号呢?

原因如下: 

  • 首先,并不是所有的进程都需要提供网络服务。因此,对于网络模块而言,如果用PID来标识网络服务进程,那么操作系统是不是还需要判断哪些进程是进行网络服务的, 这会增加系统的复杂性和开销,对于要增加成本的事情,操作系统为什么要做呢?
  • 其次, PID 是属于进程管理模块的, 而端口号是属于网络通信的一部分。 如果在网络中用 PID 来标识进程,那么就代表着将网络模块和进程管理模块强耦合在一起,万一未来进程管理模块出现变更,那么网络模块是不是也要改,这样的设计不利于系统的灵活性和扩展性。

因此,出于系统复杂度和耦合度的角度, 网络模块需要有一个端口号来标识进程的唯一性,将网络功能和进程管理模块进行解耦,降低系统的复杂性和维护成本,同时也提高了系统的可扩展性和灵活性。

通过端口号,不同的网络服务进程可以并行地提供各自的网络服务,而无需过多考虑系统内部的进程管理机制。

2.5. netstat 命令

netstat 是一个用来查看网络状态的重要工具。

语法:netstat [选项]

常用选项:

n:拒绝显示别名, 用于显示数字格式的IP地址和端口号;

l:仅列出处于 Listen 状态的网络服务;

p:包含 PID/Program name 信息;

t:仅显示 TCP 的网络服务;

u:仅显示 UDP 的网络服务;

a:显式所有连接状态的服务,包括LISTEN、ESTABLISHED、TIME_WAIT等等。

对于有些网络服务,可能需要提升权限,才能看到更多的信息,如下: 

2.6. pidof 命令

pidof:通过一个进程名,获得进程id;

语法:pidof  [进程名]

会得到一个该进程的PID;

pidof myserver | xargs kill -9

pidof 命令用于查找指定服务进程的PID,然后通过管道将结果传递给kill命令。但由于,管道是将 pidof 进程的输出做为 kill 进程的输入,注意,而此时的 kill 命令需要的是命令行参数而不是标准输入的内容。因此这时候就需要使用 xargs 命令,它可以将标准输入的内容转换成命令行参数,并传递给 kill 命令,从而向指定服务进程发送特定信号。

标准输入: 代表的是特定文件。

命令行参数: 是 main () 的参数。

3. 前置性认识

接下来,我们就要正式进入传输层了, 就要真正的揭示UDP/TCP的底层细节问题, UDP为次,TCP为主;

同时,我们也知道, 传输层是位于应用层和网络层之间的。

应用层的数据并不是直接发送给对端主机的应用层, 而是将应用层的数据拷贝给传输层协议的缓冲区中,然后根据协议栈向下封装,通过网络发送给对端主机;对端主机收到数据后,传输层会将数据从网络层接收并进行解包,然后再将数据向上交付给对应的应用层。

因此,我们对于 UDP/TCP 都要谈论两个问题:

  • UDP/TCP 是如何区分报头和有效载荷的。 只要清楚了如何区分报头和有效载荷, 我就知道,如何对报头和有效载荷进行分离以及如何封装报头的。
  • UDP/TCP 如何向上交付。

4. UDP 协议

4.1. UDP的基础认识

UDP 报文格式如下:

对于UDP而言, 它是如何区分报头和有效载荷的呢?

UDP采用的是定长包头, 通过固定长度的报头 (8字节),来区分一个UDP报文中的报头和有效载荷。因此, 对于一个UDP报文而言, 前八个字节就是报文的报头, 后面都是有效载荷。

那UDP是如何向上交付的呢?

UDP在向上交付数据时,会根据UDP数据报文头部中的目的端口号信息,将数据交付给目标进程。这是因为在网络通信中,进程通过绑定端口号来监听网络上的数据,并且这个端口号是唯一的标识符。因此,UDP在接收到数据后,根据目的端口号确定了数据应该交付给哪个目标进程。

可是,作为一个接收方, 怎么知道UDP报文中哪一个是源端口号、哪一个是目的端口呢?

因为这是协议,既是一种约定,UDP报头是八字节,客户端知道,服务端也知道,且前16个比特位就是源端口,接下来的16个比特位就是目的端口, 这是一种约定,即协议。

为什么我们在编写应用层, 定义端口号时候, 都用的是 uint16_t 呢?

因为UDP协议用的端口号是16位的,而UDP协议是基于操作系统的,而操作系统提供了一系列的系统调用接口(比如socket接口)来支持网络通信,应用层通过这些接口与网络进行交互,因此,为了与UDP协议和操作系统保持一致,应用层需要使用16位的数据类型来定义端口号。

UDP是如何正确的提取整个完整报文的呢?

UDP报文头部中的16位UDP长度字段指示了整个UDP数据报文的长度,包括报头和数据部分。因此,通过提取UDP长度字段的数值,并减去8字节(UDP报头的大小),就可以得到UDP数据报文的有效载荷大小,即有效载荷的长度。

因此接收方可以根据UDP报文头部中的长度字段来正确提取整个完整的UDP数据报文,即UDP本身就能保证接收方获取一个完整的UDP报文,故我们说UDP是面向数据报的。

4.2. 理解UDP报文本身

这里的UDP报头如下 (用以举例):

struct udp_hdr
{
	uint32_t src_port : 16;
	uint32_t dst_port : 16;
	uint32_t udp_len : 16;
	uint32_t udp_check : 16;
};

未来我们所见到的所有报头都是位段,只不过位段中的字段不一样罢了。

注意,上面只是实现的大致思路,但实际上我们知道,位段有一个缺陷:可移植性太差,但是内核依旧采用位段来定义报头,并且我们之前自己定义协议时,也说过,建议不要定义结构化的数据,因为结构化的数据会存在内存对齐和大小端等问题,但是内核就这样做了,它的解决方案很复杂 (包括各种条件编译等等),它就是为了最大限度地减少内存消耗,让操作系统在有限的资源下运行尽可能多的任务,因为操作系统是所有软件都要用的基础设施,所以设计者在设计时,用尽了心思,以达到更好的效果。

有了上面的理解,我们需要在理解一下协议是如何封装的: 

当应用层将数据向下交给传输层时 (本质上是拷贝的过程),假如此时的传输层协议是UDP,那么操作系统就会开辟一段空间, 并在内核中实例化一个UDP报头,例如: struct udp_hdr hdr = {10000, 20000, 0, 0};并将应用层的数据与该报头一起封装成一个UDP数据报。这个过程涉及到内存的开辟和拷贝,以及报头中相关字段的更新,如UDP报文长度和校验和,而这就是一个UDP报文,即这就是一个封装的过程。

有了封装的理解, 我们也可以类比到解包的过程,

UDP数据报,在操作系统看来,本质上就是一个对象,因此,我们可以得到这个对象的起始地址,直接访问前八个字节,在前八个字节中找到UDP长度,用这个UDP长度减去八字节,得到有效载荷的长度,然后,可以使用相关的拷贝函数将有效载荷从UDP数据报中拷贝到应用层的缓冲区中,从而将报头和有效载荷分离开来。而这就是一个解包的大致过程,因为它将数据报分解成了其组成部分:报头和有效载荷。当然,操作系统在实际操作中肯定更为复杂,因为它要考虑更多的细节,但这是它的大致思路。

4.3. UDP字段

  • 源端口:代表这个UDP数据报是哪个进程发送的;
  • 目的端口:代表这个UDP数据报是发送给哪个进程的;
  • UDP长度:代表UDP数据报的整体大小 (报头 + 有效载荷)。UDP的报头固定为8个字节,故UDP长度最小是8字节 (只包含报头,无有效载荷);
  • UDP校验和: 这个字段用于检测UDP数据报在传输过程中是否发生了错误。如果接收方计算出的校验和与UDP数据报中的校验和不匹配,那么该数据报将被认为是损坏的并被丢弃;

4.4. UDP相关特性

  • 无连接UDP是一种无连接的协议,通信的双方在发送数据之前不需要建立连接。每个UDP数据报都是独立的,发送方发送数据时不需要等待接收方的确认,也不需要保留连接状态信息。
  • 不可靠UDP是一种不可靠的协议,它不提供数据可靠性的保证。UDP数据报在传输过程中可能会丢失、重复、失序或损坏,而且UDP本身不提供任何重传、确认、流量控制等机制。
  • 面向数据报面向数据报是指每个数据报都是独立的,UDP 不会对应用层交给它的报文进行拆分或合并,而是按照应用层传递给它的数据报原样发送。这意味着 UDP 不会对数据进行任何拆分或者组合操作,而是以数据报的形式将数据发送出去。简而言之,数据怎么给你的,你就怎么给我发出去。

无连接和面向数据报很好理解,但在这里要对不可靠强调一下。

  • 不可靠并不是UDP的缺点,而是它的特点;
  • 数据在进行长距离传输时, 如果要保证可靠性,那么就意味着需要做更多的工作 (比如重传、确认、流量控制等机制),这些机制会增加协议的复杂性,而一旦复杂,那么其使用成本和维护成本都会更高;
  • 而不可靠,意味着它会做更少的工作,只提供基本的数据传输服务,而不保证数据的可靠性,也就不考虑其他的机制,因此它就更简单,使用和维护成本就更低。

4.5. UDP的缓冲区

如何理解我们之前所学的IO接口,诸如 sendto / recvfrom、read / write、 recv / send 等等这些IO接口呢?

  • 不要认为这些函数是在网络中进行数据收发,例如,sendto 是将数据中直接发送给网络的,recvfrom 是从网络中读取数据到应用层的。
  • 上面的认识是错误的。
  • 上面的这些函数本质上都是拷贝函数。 例如, sendto 只是将应用层的数据拷贝给了内核层的缓冲区,如果传输层协议提供了缓冲区,那么就拷贝传输层协议的缓冲区;而 recvfrom 只是将传输层协议的缓冲区的数据拷贝到了应用层的缓冲区 (即用户自己定义的缓冲区)。
  • 可是,将应用层数据拷贝到传输层的缓冲区就完了吗?
  • 那么传输层的缓冲区的数据什么时候发送、发多少, 出错了怎么办?
  • 这些问题谁关心呢? 操作系统帮你关心,即传输层的协议解决这些问题。
  • 传输层的协议(如TCP或UDP)负责管理传输层缓冲区中的数据,包括何时发送数据、发送多少数据以及如何处理发送过程中的错误等问题。应用层只是将数据拷贝给传输层的缓冲区,至于后续的传输过程以及错误处理等任务,都由传输层协议来完成。
  • 因此,传输层的协议承担了管理数据传输的责任,而应用层只需将数据传递给传输层,无需关心具体的传输细节和错误处理等问题。
  • UDP 协议没有发送缓冲区。 调用 sendto 会直接将应用层数据交给内核,内核再将该数据传给网络层协议进行后续的传输动作;
  • UDP 协议具有接收缓冲区。 但这个缓冲区无法保证收到的UDP数据报的顺序和发送UDP数据报的顺序一致,即存在乱序问题; 且如果接收缓冲区如果满了, 再来UDP数据报则会直接被丢弃。

4.6. 全双工 vs 半双工

全双工:既可以收数据,又可以发数据,收发可以同时进行;

半双工:如果在收,就不能发;如果再发,就不能收, 收发并不能并行。

UDP和TCP都是全双工的协议,这意味着它们都支持在任意时刻进行并发的数据收发。

在UDP和TCP协议中,发送和接收是独立进行的。发送端可以在任何时候发送数据,而接收端可以在任何时候接收数据,这使得它们都具有全双工通信的能力。

那么UDP和TCP是如何支持全双工的呢?

只要发送和接受操作是相互独立的 (发送缓冲区和接收缓冲区并不冲突),那么就可以支持全双工。具体来说:

  • UDP:虽然UDP没有专门的发送缓冲区,但发送操作是立即执行的,它不会阻塞接收操作。这意味着在UDP通信中,发送数据时并不会影响接收缓冲区,因此UDP可以实现全双工通信。
  • TCP:TCP有发送缓冲区和接收缓冲区,但发送和接收操作是独立进行的。发送数据时,TCP会将数据放入发送缓冲区并立即返回,不会阻塞接收操作。同样,接收数据时,TCP会从接收缓冲区读取数据并立即返回,也不会影响发送操作。这使得TCP也能够实现全双工通信。

总的来说,UDP和TCP之所以能够支持全双工通信,是因为它们在发送和接收操作上相互独立,不会相互阻塞。

4.7. UDP 使用注意事项 

UDP协议的数据报文有一个最大长度限制 (因为它是16位的整数),即64K(包括UDP头部)。在当今的互联网环境下,这个限制可能会限制数据传输的效率和灵活性,特别是在需要传输大量数据的情况下。

  • 如果需要传输的数据超过了UDP数据报的最大长度限制,就需要在应用层进行手动的分包和多次发送。
  • 发送端将数据分割成适当大小的数据块,然后分别封装成UDP数据报进行发送。
  • 在接收端,需要接收所有的UDP数据报,并且按照顺序将它们拼装成完整的数据。
  • 这就需要在应用层处理数据的分段和组装,增加了复杂性和开销

4.8. 基于UDP的应用层协议 

  • NFS:网络文件系统
  • TFTP:简单文件传输协议
  • DHCP:动态主机配置协议
  • BOOTP:启动协议(用于无盘设备启动)
  • DNS:域名解析协议

当然,也包括用户在编写UDP时自定义的应用层协议。

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

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

相关文章

数据结构进阶篇 之 【并归排序】(递归与非递归实现)详细讲解

都说贪小便宜吃大亏,但吃亏是福,那不就是贪小便宜吃大福了吗 一、并归排序 MergeSort 1.基本思想 2.实现原理 3.代码实现 4.归并排序的特性总结 二、非递归并归排序实现 三、完结撒❀ –❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀…

如何使用单片机 pwm 控制 mos 管?

目录 选择适合的硬件 连接电路 编写代码 参考示例 程序一 程序二 测试与调试 注意事项 使用单片机(如常见的Arduino、STM32等)通过PWM(脉冲宽度调制)控制MOS管(金属氧化物半导体场效应管)是一种常见…

Java中的集合(二)

一、回顾上期 上一篇讲到在Java中,集合和容器是非常重要的概念,用于存储和操作数据。在集合中,有单列集合和双列集合两种类型。我们在上一篇将单列集合中的list类讲完了,这一篇将会将集合中剩余部分介绍完,话不多说&am…

备战蓝桥杯---刷二分与前缀和题

刷点题~ 1.二分多路归并算法 对于每一个技能,我们把它看成一个等差数列,我们把所有可能都放到一个集合里,排个序,取前m个大即可,现在考虑优化,假如m不是很大,我们直接用优先队列即可&#xff0…

单细胞RNA测序(scRNA-seq)SRA数据下载及fastq-dumq数据拆分

单细胞RNA测序(scRNA-seq)入门可查看以下文章: 单细胞RNA测序(scRNA-seq)工作流程入门 单细胞RNA测序(scRNA-seq)细胞分离与扩增 1. NCBI查询scRNA-seq SRA数据 NCBI地址: https…

继承.Java

目录 1,概述 1.1继承的含义 1.2什么时候用继承 1.3继承的好处 1.4继承的特点 2,继承的格式 3,可以继承哪些内容 4,成员方法和成员变量的访问特点 5,构造方法的访问特点 6,this,super…

windows版本-idea中下载的java版本在哪

1、点击idea的file-projectStructure 进入: 通过电脑目录进入该目录 找到bin目录,copy该目录地址 copy下来之后设置到系统环境变量中

C#项目引用解决方案中其他项目dll时,出现黄色感叹号的解决方案

问题引入 今天拿着老师傅的老项目,需要做通讯调试,说测试一下,便添加了一个项目A来编写结构体,然后在窗体程序项目B中引用A,发现B一引用A,在B项目的引用下面A就多了个黄色感叹号,一编译B项目&am…

瑞_Redis_商户查询缓存

文章目录 项目介绍1 短信登录2 商户查询缓存2.1 什么是缓存2.1.1 缓存的应用场景2.1.2 为什么要使用缓存2.1.3 Web应用中缓存的作用2.1.4 Web应用中缓存的成本 2.2 添加Redis缓存2.2.1 背景2.2.2 缓存模型和思路2.2.3 代码实现2.2.4 测试附:IDEA控制台输出自动换行设…

色域(BT2020/BT709/sRGB/DCI-P3/Rec.709/NTSC)

什么是色域 色域是对一种颜色进行编码的方法,也指一个技术系统能够产生的颜色的总和。在计算机图形处理中,色域是颜色的某个完全的子集。一般来说,高端投影仪和电视都会强调色域范围和对比度,而不是唯亮度标准论。 自然界可见光…

面试算法-139-盛最多水的容器

题目 给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水量。 说明:你不能倾斜容器。…

Sybase ASE中的char(N)的坑以及与PostgreSQL的对比

1背景 昨天,一朋友向我咨询Sybase ASE中定长字符串类型的行为,说他们的客户反映,同样的char类型的数据,通过jdbc来查,Sybase库不会带空格,而PostgreSQL会带。是不是这样的?他是PostgreSQL的专业大拿,但因为他手头没有现成的Sybase ASE环境,刚好我手上有,便于一试。 …

(学习日记)2024.04.01:UCOSIII第二十九节:消息队列实验(待续)

写在前面: 由于时间的不足与学习的碎片化,写博客变得有些奢侈。 但是对于记录学习(忘了以后能快速复习)的渴望一天天变得强烈。 既然如此 不如以天为单位,以时间为顺序,仅仅将博客当做一个知识学习的目录&a…

LearnOpenGL_part1

创建窗口 - LearnOpenGL CN (learnopengl-cn.github.io) 最原始的黑框框&#xff1a; #include <glad/glad.h> #include <GLFW/glfw3.h> #include <iostream> int main() {glfwInit();//初始化GLFWglfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//配置G…

亚马逊AWS永久免费数据库

Amazon DynamoDB 是一项无服务器的 NoSQL 数据库服务&#xff0c;您可以通过它来开发任何规模的现代应用程序。作为无服务器数据库&#xff0c;您只需按使用量为其付费&#xff0c;DynamoDB 可以扩展到零&#xff0c;没有冷启动&#xff0c;没有版本升级&#xff0c;没有维护窗…

如何同时安全高效管理多个谷歌账号?

您的业务活动需要多个 Gmail 帐户吗&#xff1f;出海畅游&#xff0c;Gmail账号是少不了的工具之一&#xff0c;可以关联到Twitter、Facebook、Youtube、Chatgpt等等平台&#xff0c;可以说是海外网络的“万能锁”。但是大家都知道&#xff0c;以上这些平台注册多账号如果产生关…

Codeforces Round 930 (Div. 2) ---- E. Pokémon Arena ---- 题解

E. Pokmon Arena&#xff1a; 题目大意&#xff1a; 思路解析&#xff1a; 可以想到的是&#xff0c;可以用最短路来解决这个问题&#xff0c;但是如果简单的建图的话&#xff0c;时间复杂度将会达到 O(n*n*m)&#xff0c;我们考虑怎么减少图中边的个数。 我们考虑一个颜色&…

C语言中的字符与字符串:魔法般的函数探险

前言 在C语言的世界里&#xff0c;字符和字符串是两个不可或缺的元素&#xff0c;它们像是魔法般的存在&#xff0c;让文字与代码交织出无限可能。而在这个世界里&#xff0c;有一批特殊的函数&#xff0c;它们如同探险家&#xff0c;引领我们深入字符与字符串的秘境&#xff0…

探索GlassWire:网络安全与流量监控软件

名人说&#xff1a;东边日出西边雨&#xff0c;道是无晴却有晴。——刘禹锡 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 一、软件介绍1、GlassWire&#xff08;免费版本&#xff09;2、核心特点 二、下载安装①…

想拿高薪?云计算或许是你的跳板!

随着科技的不断进步&#xff0c;云计算作为一项重要的技术趋势&#xff0c;正引领着整个行业的快速发展。越来越多的人开始关注云计算领域&#xff0c;希望通过学习和掌握这一技能来获得更高的薪资。那么&#xff0c;为什么选择云计算作为职业发展方向&#xff1f;学习云计算又…