当前位置: 首页 > news >正文

UDP_TCP

目录

  • 1. 回顾端口号
  • 2. UDP协议
    • 2.1 理解报头
    • 2.2 UDP的特点
    • 2.3 UDP的缓冲区及注意事项
  • 3. TCP协议
    • 3.1 报头
    • 3.2 流量控制
    • 2.3 数据发送模式
    • 3.4 捎带应答
    • 3.5 URG && 紧急指针
    • 3.6 PSH
    • 3.7 RES

1. 回顾端口号

  • 在 TCP/IP 协议中,用 “源IP”, “源端口号”, “目的IP”,“目的端口号”,“协议号” 这样一个五元组来标识一个通信(可以通过 netstat -n 查看)。

  • 端口号范围划分:

    • 0 - 1023:知名端口号,HTTP,FTP,SSH等这些广为使用的应用层协议,他们的端口号都是固定的。

      ssh(22),ftp(21),telnet(23),http(80),https(443)

    • 1024 - 65535:操作系统动态分配的端口号。客户端程序的端口号,就是由操作系统从这个范围分配的。

  • cat /etc/services:看到知名端口号。

  • 两个问题(详细见 网络基础(二)):

    • 一个进程是否可以bind多个端口号?  ------ 可以。
    • 一个端口号是否可以被多个进程bind?   ------ 不可以。

2. UDP协议

在这里插入图片描述

  • 以UDP为例:当我们在客户端的应用层,通过 sendto 系统调用,将数据发送到服务端,站在网络协议栈的角度看待,该数据实际上是先被拷贝到传输层(传输层属于OS),而这部分数据就是 UDP 中看到的数据,应用层的报文经由传输层时,OS会封装一层传输层的报头,即 UDP 报头。

    分装报头时,发送端会随机形成一个源端口,并填充目的端口号。其中的 UDP 长度代表的是整个 UDP 报文的长度,检验和则是检验整个报文在传输过程中是否出错。

    因此,我们过去在 udp_socket 编程时,客户端需要在发送请求的同时,填充服务端的端口号,以及定义端口号时,我们采用的类型是 uint16_t,这一切都是源于 UDP 的报头决定的!

  • 而因为网络通信时,报文在协议栈中自顶向下是要分装的,最后再自底向上解包分用。因此,我们需要解决

    • 报头和有效载荷的分离问题:固定报头长度。
    • 有效载荷是如何向上交付的问题:绑定目的端口号。
    • UDP 是面向数据报的,如何保证接收到的报文是完整的? ------ 通过报头长度确定,如果报头长度小于8字节,报头都有问题,整个报文直接丢弃;大于8字节,UDP长度 - 报头长度 = 数据长度。

2.1 理解报头

  • 我们在各种教科书上看到的报头都形如上图,但是报头究竟是个什么东西呢?

    一个描述报头的结构体,所谓报头,就是一个结构化的数据。

    struct udphdr {uint16_t src_port, dst_port;uint16_t udp_len, checksum;
    }
    

    但是,一个服务器是同时对接多个客户端的,因此服务器内是会存在大量的报文的,因此操作系统内可能积攒大量的报文,可能还没有向应用层进行交付,那么操作系统就需要对这些 UDP/TCP 报文管理起来。

    内核中存在一个 sk_buff 结构体,其中有 *data、*tail 两个字段的指针(指向同一位置),并且在内核中定义一段缓冲区,用户保存接收到的报文数据。假设应用层通过 sendto 将 “hello” 发送到传输层,那么在拷贝到传输层时,*data 指针就向前移动 5 个字节,用于存储上层发送的数据。接着,还需要定义一个 udphdr 报头对象,*data 指针继续向前偏移 8 个字节,用于存储报头数据。这就是 UDP 封装。

    而 UDP 层可能积攒了很多的报文数据,只需要通过 struct sk_buff *next 字段,将报文以链表的形式组织起来。这样一来,对报文的管理,就转变为对链表的增删查改。

  • 更重要的是,不同端的主机通信,采用的也是网络协议栈,同样也有传输层。什么是协议?双方都需要按照同样的规则、同样的标准来通信。因此,在不同端,无论收发信息,采用的都是 udphdr 这样的描述结构体,双方使用同样的数据类型来解释收到的 UDP 报头的 8 个字节。因此协议就是结构化数据,协议就是一种约定。

2.2 UDP的特点

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

  • 不可靠:没有确认机制,没有重传机制;如果因为网络故障该段无法发到对方,UDP协议层也不会给应用层返回任何错误信息。

  • 面向数据报:不能够灵活的控制读写数据的次数和数量(在向上层交付时,UDP 清楚的报文的有效载荷是多少个字节)。

    应用层交给UDP多长的报文,UDP原样发送,既不会拆分,也不会合并。

    例如:用UDP传输100个字节的数据,如果发送端调用一次 sendto,发送100个字节,那么接收端也必须调用对应的一次 recvfrom,接收100个字节,而不能循环调用10次 recvfrom,每次接收10个字节。

  • UDP的 socket 既能读,也能写,这个概念叫做全双工。

2.3 UDP的缓冲区及注意事项

  • UDP没有真正意义上的发送缓冲区,调用 sendto 会直接交给内核,由内核将数据传给网络层协议进行后续的传输动作。

  • UDP具有接收缓冲区,但是这个接收缓冲区不能保证收到的 UDP 报的顺序和发送 UDP 报的顺序一致(即可能先发的后收到)。如果缓冲区满了,再到达的UDP数据就会被丢弃。

  • 我们注意到,UDP 协议首部中有一个16位的最大长度,也就是说一个 UDP 能传输的数据最大长度是64K(包含UDP首部)。 然而 64K 在当今的互联网环境下,是一个非常小的数字,如果我们需要传输的数据超过64K,就需要在应用层手动的分包,然后多次发送,并在接收端手动拼接。

3. TCP协议

3.1 报头

在这里插入图片描述

  • 同样的,TCP 报头在内核中也是一种结构化的字段。

  • 4 位首部长度:取值范围 [ 0000 , 1111 ] = [ 0 , 15 ] [0000,1111] = [0, 15] [00001111]=[0,15],单位是 4个字节,即 4 位首部长度实际的取值范围为 [ 0 , 15 ] ∗ 4 = [ 0 , 60 ] [0, 15] * 4 = [0,60] [0,15]4=[060],也就意味着选项字段的大小,最多为 40 40 40 字节。

    假设 TCP 报头的长度为 20 20 20 字节,那么首部长度即为 x ∗ 4 = 20 x * 4 = 20 x4=20 x = 5 x = 5 x=5 ,即 x = 0101 x = 0101 x=0101

    有了首部长度 x x x,默认先读取前 20 20 20 字节,提取首部长度字段,如果 x = 20 x = 20 x=20,即代表报头为 20 20 20 字节;如果 x > 20 x > 20 x>20 x − 20 = x - 20 = x20= 选项字段长度,剩下的就是数据长度。这样一来,即解决了报头和有效载荷的分离问题。

    与 UDP 协议同理,当应用层将数据通过 sendto 传递给传输层后,传输层申请 sk_buff 缓冲区,接着将数据从用户空间拷贝到 sk_buff 缓冲区,再为 TCP 报文构建协议报头并填充字段,最后将报头添加到 sk_buff 缓冲区中。至此,完成对 TCP 报文的封装。

  • 6位标志位(后面详讲):

    • URG: 紧急指针是否有效
    • ACK:确认号是否有效(即应答报文设置的标志位)
    • PSH:提示接收端应用程序立刻从 TCP 缓冲区把数据读走
    • RST:对方要求重新建立连接,我们把携带 RST 标识的称为复位报文段
    • SYN:请求建立连接,我们把携带 SYN标识的称为同步报文段(用于三次握手建立连接)
    • FIN:通知对方,本端要关闭了,我们称携带 FIN 标识的为结束报文段(四次挥手关闭连接)

3.2 流量控制

  • 与 UDP 不同的是,TCP 拥有独立的 发送和接收 缓冲区。并且,单独的客户端既可以同时发送和接收,因此 TCP 是全双工通信。

在这里插入图片描述

  • 假设 TCP 通信的双方,一方发的特别快,另一方处理数据比较慢,但是发送方仍一直持续的发送,那么接收缓冲区就会被写满。但是发送方对于接收缓冲区已经被写满并不知情,所以继续在发送数据,但是数据又存不下了,于是报文被直接丢弃了?

    丢弃后,虽然 TCP 后续可能对该报文进行重传。但是,可能这份报文可能经过无数个路由器,转发了无数次报文,好不容易到才到达目的地,花费这么大的代价,结果被丢弃了??这种做法是不合理的!

    面对上述情况,本质问题就是,发送方无法得知接收方缓冲区的情况。如果接受方来不及接收报文了,发送方 放缓 或 暂停发送,问题就能够得到解决,而这种解决方法称为 流量控制

    在实际 tcp_socket 通信时,我们并没有遇到这类问题,因为上面的工作,已经由发送方的 TCP 完成了,用户并不需要关心,由 TCP 全权负责,这也是为什么 TCP 称为 传输控制协议!在实际的网络通信中,用户层调用 sendto 将数据传递到传输层后,在上层,我们就认为数据已经发送出去了,而实际上,可能数据还存储在本地操作系统的缓冲区内,还未进行发送。

  • TCP 为了保证传输的可靠性,协议要求 TCP 的接收方必须在收到报文后进行确认(向客户端进行响应反馈), 即 确认应答机制

    需要注意的是,假设发送的数据为 " h e l l o " "hello" "hello",真正发送的时候,可不仅仅只有数据,而是将数据封装在报文内,将整个 TCP 报文发送给对方。同样的,接收方在给发送方进行应答时,也是发送的一个 TCP 报文,同时在报头中设置了 ACK 标志位(ACK标志位置 1 1 1)。

  • 16 位窗口大小: 记录发送方接收缓冲区的剩余空间大小。

  • 那么如何进行流量控制呢?? ------ 发送方能够得知接收方的接收能力。

    而接收缓冲区接收能力的强弱,以剩余的空间大小为衡量。因此当接收方在向发送方进行应答时,在应答的报头中的 窗口大小字段,填充自己接收缓冲区的剩余空间大小,那么发送方就能够清楚的进行传输控制了!

    即,窗口大小是用于流量控制的字段!

    上述一切关于流量控制的方式、细节,全部由 TCP 通信的双方的操作系统协商完成!

  • 当接收缓冲区被写满,发送方也就停止发送,但是上层用户可不关心!上层用户还是继续向传输层写写写,那当发送缓冲区也被写满了呢??

    这就是典型的生产消费模型,消费者不消费了,生产者就进行要阻塞!即进程就要进入阻塞状态,其本质就是进程在等待 OS 进行发送。进程是一个执行流,OS 也是一个执行流,这就是两个执行流在进行同步!

    在这里插入图片描述

  • 即便 TCP 是传输具有可靠性的,但也无法保证 100% 可靠的网络通信。

    假设 C 端给 S 端发送第一条信息,但是在这条信息发送出去,到 S 端进行应答之前这段时间,对于 C 端,它是无法确认这次的报文对方是否收到。

    当 S 端给 C 端应答第一条信息后,那么就轮到 S 端无法确认它发出去的报文对方是否收到。那如果要做到 S 端也能够确认自己的报文对方收到了,那就需要 C 端继续发送一次应答,那这次应答的报文,对于 C 端,它又无法确认对方是否收到(因为还没收到对方的应答)。

    所以这个是一个死循环,永远无法确认最新的一条信息对方是否收到了,也即最新的一条消息的可靠性其实是无法保证的。但是!可以保证除了最后一条信息之前的所有信息的可靠性,如上图所示,① 和 ② 都是收到了应答,因此除了最新的 ③ 信息,其它都能够保证可靠性。

2.3 数据发送模式

  • 像我们上面介绍的通信方式,C 端给 S 端发送数据, S 端需要给 C 端进行应答,反之同理。这些都是串行发送的,通信效率比较慢。

    在这里插入图片描述

    这是 TCP 发送数据常见的方式,将发送时间进行重叠,并发的发送多份报文,并且规定每个报文都需要进行应答,保证可靠性的同时提高效率。

  • 由于网络的实际情况错综复杂,因此无法保证接收顺序与发送顺序一致,那么就可能导致数据乱序的问题(可能一份数据拆分为多个报文进行发送),而乱序是不可靠的一种表现,因此在同时发送多份报文的情况下,需要保证报文按序到达。

    即报头内的 32 位序号:给报文携带编号。接收方可以根据报头中序号,对接收到的报文进行排序,即可保证报文按序到达。

  • 还有一个问题是:C 端发了 4 份报文,S 端是需要给 C 端应答 4 次的,那么 S 端的哪一次应答是对 C 端的哪一次报文做的应答呢???如果不能解决这个问题,那么当发送方发了 10 个报文,最终只收到了 9 个应答,那发送方就无法得知,自己发送的 10 个报文里面,到底是哪个报文丢了!导致也无法进行后续补发报文的操作。

    因此报头中还有另一个字段 ----- 32位确认序号:用于记录历史上发送方发送的哪些报文已经被接收方所接收,由接收方在应答报头中填充,对应收到报文的序号值 + 1。

    确认序号之前的所有报文已经被接收方收到。例如:确认序号301代表的含义是序号300 200 100 的报文都已经被 S 端收到了。之所以这样设计的原因是:不管是数据还是应答,在网络传输中都有可能丢失,假设 S 端前三次报文都收到了,但是这三次应答都丢失了,最后一份报文的应答 401 没有丢失,那么 C 端在接收到 S 端的 401 应答时,即可以得知 4 份报文, S 端都接收到了。换言之,这样设计,可以允许少量的应答丢失。

3.4 捎带应答

  • 看似一切完美,在应答的时候明明可以继续用 32 位序号来保障应答的可靠性,为啥还要多设计出一个32位确认序号呢??

    要清楚,我们至始至终,为了方便理解,一直都是以单向通信为例。但实际上的通信是双向的,即 C 端 在向 S 端发数据的同时, S 端 也在给 C 端发数据。

    那么 S 端 就需要在应答 C 端的同时,发送自己的数据。如果只有一个 32 位序号,那么应答 和 发数据 这两件事就需要分开来完成,即 S 端需要向 C 端发送两次报文。而有了 32 位确认序号后,这两件事可以同时完成,即发送数据的同时顺带给 C 端应答了!这就叫做捎带应答!!

    实际通信时,大部分报文都既是数据,又是对历史报文的应答确认!

    总结:TCP 在保证可靠性的同时,还会进行各种提高效率的设定(数据并发发送、捎带应答)!只不过这些工作都有 TCP(内核) 自主完成,用户并不知情。

3.5 URG && 紧急指针

  • 标志位:用于标识不同的报文类型。

    服务器是同时面对多个客户端的,即需要同时处理来自多个客户端的 TCP 报文,而这些报文可能包含连接建立、连接断开、正常数据传输或异常数据等类型。那么服务器就必须具备识别不同报文类型的能力,才能根据报文类型执行相应的处理动作。

  • 我们上面说过,发送方可能同时一次性发送一批报文,并且这批报文的数据是有顺序的,那么就必须保证这批报文按序到达,而按序到达的本质就是队列(先发先收)。但不妨有时候会有一些紧急任务,那么在按序到达的规则下,即便是紧急任务,也要排队!但所谓紧急任务,肯定是需要尽快处理、提前被处理的。

    因此面对这种情况,URG 标志位置 1,表明该报文是紧急报文。

  • 16位紧急指针:记录紧急数据在有效载荷中的偏移量。

    收到报文,先查看标志位,如果 U R G = 1 URG = 1 URG=1,那么根据紧急指针查看紧急数据(紧急数据只有一个字节)。

    紧急任务的场景:假设发送方上传一批数据,但是上传过程中发现上传错了,而此时接收方的缓冲区已经积攒了大量的报文还没被处理,这种情况就可以发送紧急指针,示意对方立即终止或暂停上传行为(通过一些固定的标志信息反馈)(如果直接关闭连接,那么接收方需要把缓冲区的数据全部读取完,才能得知发送方已经关闭连接)。

    再者,例如当发现服务器运行速度比较慢时,通过给服务器发送紧急指针,进行服务检测。

  • 在发送 send 和 接收 recv 的第三个参数 flag,就会提供一些标志位,例如 MSG_OOB 就表示紧急数据。

     ssize_t recv(int sockfd, void *buf, size_t len, int flags);MSG_OOBThis flag requests receipt of out-of-band data that would not be received  in  the  normal  data  stream.
    

3.6 PSH

  • 在讲流量控制的时候,我们讲过,当接受发给发送方应答的同时,报头中的窗口大小会记录接收方缓冲区剩余空间大小,以便发送方进行传输控制。

    假设接收方上层 http 处理数据比较耗时,导致接收缓冲区被写满,随后接收方在应答报文中将窗口大小设置为 0,告知对方无法接收更多数据。一段时间后,接收方的上层处理了一些数据,缓冲区腾出一些空间,但此时的发送方并不知情,还在傻傻的阻塞等待。

    因此,为了避免这种情况,发送方会定期发送空闲时间较长的询问报文(这种方式效率较低,因为它依赖超时来触发询问),然后等待接收方的应答。另一方面,当接收方的缓冲区的剩余空间由 0 0 0 变为 ! 0 !0 !0 时,接收方也会主动向发送方进行窗口大小的更新报文。

  • 这里所谓的询问报文,也是完整的 TCP 报头,同时将 PSH 标志位置 1。即 PSH:告知对方,尽快将数据向上层交付。

    但 PSH 不仅仅应用于询问报文中,当数据需要被尽快交付时,也可以使用。最典型的案例就是,xshell 远程连接远端服务器时,为了保证更好的用户体验,xshell 尽可能的让用户输入的每一条指令携带 PSH 标志位,让上层的 ssh 尽快交付解释。

3.7 RES

  • 我们一直在说通信,但建立 TCP 通信的前提是建立连接,而建立连接就需要三次握手。

    虽然 TCP 是保证可靠性的,但不代表三次握手就必须是成功的,也可能是失败的!保证的不是数据 100% 到达目的地,而是数据到达目的地了 或者 数据传输异常了,TCP 需要知道。

    在这里插入图片描述

  • 三个报文的前两个报文丢失都不影响,假设客户端连接建立请求的报文丢失了,服务端没有收到(服务端知情),那么也就不会给应答。客户端收不到服务端的应答,也就同样知情报文丢了(要么是自己的,要么是对方的应答报文),那么客户端就会进行报文重发。而假设服务端的报文丢了,虽然服务端自己不知情,但是客户端没收到,客户端是知情的,它就不会给服务端发送应答报文,那么服务端收不到应答报文,服务端也知情了。

    最麻烦的是最后一次 ACK,假设最后一次客户端的 ACK 丢了,但客户端并不知情。站在客户端的角度,客户端认为,最后一次 ACK 报文发送出去即连接建立成功,而服务端需要等到接收了报文才认为连接建立成功。这种情况就会导致双端连接建立认知不一致的问题。

    因为客户端认为连接建立好了,所以它就开始向服务端发送数据,服务端收到数据后,脑袋大大的问号,因为它认为三次握手还没完成,于是服务端就向客户端推送一个报文,并在报头中设置 RST 标志位。客户端收到 RST 标志位的报文后,就重置连接,重新开始三次握手。

  • 因此,三次握手的最后一次,是无法保证可靠性的,即三次握手不是一定成功的,但可以通过 RST 标志位做容错处理。

    同样的, RST 也不仅仅应用于三次握手。例如当双方通信的过程中,客户端网络中断,连接被释放了。随后客户端恢复了网络环境,但服务端并不知道,于是继续向客户端发送数据。这也是双端连接建立认知不一致的情况。客户端恢复网络后,它认为连接还没建立,但服务器不知情,依旧认为连接还在。这种情况,客户端同样可以向服务器发送 RST 重置连接请求。

相关文章:

UDP_TCP

目录 1. 回顾端口号2. UDP协议2.1 理解报头2.2 UDP的特点2.3 UDP的缓冲区及注意事项 3. TCP协议3.1 报头3.2 流量控制2.3 数据发送模式3.4 捎带应答3.5 URG && 紧急指针3.6 PSH3.7 RES 1. 回顾端口号 在 TCP/IP 协议中,用 “源IP”, “源端口号”…...

Python 中常见的数据结构之二推导式

Python 中常见的数据结构之二推导式 使用推异式列表推导式字典推导式集合推导式 使用推异式 推导式是一种从已存在的序列中快速构建列表(list)、集合(set) 和 字典(dictionary)方式。Python 支持 3 种不同类型的推导式: 列表推导式;字典推导式&#xf…...

STM32 拓展 低功耗案例3:待机模式 (hal)

配置PA0的两种方式: 第一种 第二种 复制寄存器代码然后对其进行修改 mian.c /* USER CODE BEGIN Header */ /********************************************************************************* file : main.c* brief : Main program body…...

【开源社区openEuler实践】探索 Yocto-Meta-OpenEuler:嵌入式开发的强大基石

title: 探索 Yocto-Meta-OpenEuler:嵌入式开发的强大基石 date: ‘2024-11-19’ category: blog tags: Yocto-Meta-OpenEuler嵌入式系统开源项目定制化开发 sig: EmbeddedTech archives: ‘2024-12’ author:way_back summary: Yocto-Meta-OpenEuler 为嵌入式系统开…...

C++ hashtable

文章目录 1. 基本概念2. 哈希函数3. 哈希冲突及解决方法开放定址法链地址法再哈希法建立公共溢出区4. 哈希表的操作实现5. 内存管理及优化 时间复杂度理想情况(无哈希冲突或冲突极少)一般情况(考虑哈希冲突及解决方法)综合来看 以…...

JS (node) 的 ACM 模式 + debug方法 (01背包为例)

文章目录 JS 的 ACM 模式输入处理 JS dubug (01背包为例)动态输入在本地通过 Node.js 运行和调试 硬编码 Hard CodingVS Code JS 的 ACM 模式 在 JavaScript 中,ACM 模式一般通过 Node.js 的 readline 模块实现。 输入处理 使用 readline 模块监听输入。 将每行输…...

vue设计与实现-框架设计

权衡的艺术 命令式和声明式 视图层框架通常分为命令式和声明式,各有优缺。jquery是一种命令式框架。命令式框架关注过程,而声明式框架关注结果。对于vue来说,过程被vue封装了,所以vue内部是命令式的,但vue暴露给用户…...

Stable Diffusion和Midjourney有什么区别?

Stable Diffusion 和 Midjourney 主要有以下区别: 目录 费用与可访问性 设备要求 安装与使用 学习成本 图像生成效果 可控性与定制性 私密性 费用与可访问性 Stable Diffusion:开源免费,任何人都可以免费下载并自行部署使用&#xf…...

即插即用,无痛增强模型生成美感!字节跳动提出VMix:细粒度美学控制,光影、色彩全搞定

文章链接:https://arxiv.org/pdf/2412.20800 代码地址:https://github.com/fenfenfenfan/VMix 项目地址:https://vmix-diffusion.github.io/VMix/ 亮点直击 分析并探索现有模型在光影、色彩等细粒度美学维度上生成图像的差异,提出…...

面向对象分析和设计OOA/D,UML,GRASP

目录 什么是分析和设计? 什么是面向对象的分析和设计? 迭代开发 UML 用例图 交互图 基于职责驱动设计 GRASP 常见设计原则 什么是分析和设计? 分析,强调是对问题和需求的调查研究,不是解决方案。例如&#x…...

【每日学点鸿蒙知识】广告ID、NFC手机充值、CSS支持语法、PC与模拟器交互、SO热更新等

1、HamonyOS 样机获取成功返回Oaid为00000000-0000-0000-0000-000000000000? 请求授权时需要触发动态授权弹窗,看一下是不是没有触发授权弹窗。 可以参考以下代码以及文档: // ets import identifier from ohos.identifier.oaid; import hilog from oh…...

30分钟学会HTML

HTML 基本语法 HTML(HyperText Markup Language)是构成网页内容的基础。它使用一系列的标签来描述网页的结构,包括文本、图片、链接等元素。浏览器会解析这些标签并渲染成我们看到的网页。 在线体验一下 CodePen (在线 HTML 编辑器)。 千万不…...

服务器信息整理:用途、操作系统安装日期、设备序列化、IP、MAC地址、BIOS时间、系统

文章目录 引言I BIOS时间Windows查看BIOS版本安装日期linux查看BIOS时间II 操作系统安装日期LinuxWindowsIII MAC 地址IV 设备序列号Linux 查看主板信息知识扩展Linux常用命令引言 信息内容:重点信息:用途、操作系统安装日期、设备序列化、IP、MAC地址、BIOS时间、系统 Linux…...

Golang设计模式目录

go语言实现设计模式 1 文章目录: 1.1 创建型模式 1.Golang设计模式之工厂模式2.Golang设计模式之抽象工厂模式3.Golang设计模式之单例模式4.Golang设计模式之建造者模式5.Golang设计模式之原型模式 1.2 结构型模式 6.Golang设计模式之适配器模式7.Golang设计模式之桥…...

选择IT驻场外包公司,要找有哪些资质的公司

在当今数字化快速发展的时代,IT驻场外包服务成为众多企业优化运营、提升竞争力的关键选择。无论是初创企业寻求技术起步支持,还是大型企业为降低成本、专注核心业务而将部分 IT 职能外包,IT 外包公司都扮演着至关重要的角色。然而&#xff0c…...

Java List 集合详解:基础用法、常见实现类与高频面试题解析

正文 在 Java 集合框架中,List 是一个非常重要的接口,广泛用于存储有序的元素集合。本文将带你深入了解 List 接口的基本用法、常见实现类及其扩展,同时通过实际代码示例帮助你快速掌握这些知识。 👉点击获取2024Java学习资料 1…...

Arduino UNO 驱动1.8 TFT屏幕显示中文

背景 最近入手了一块1.8寸的tft屏幕&#xff0c;通过学习文档&#xff0c;已经掌握了接线&#xff0c;显示英文、数字、矩形区域、划线、画点等操作&#xff0c; 但是想显示中文的时候操作比较复杂。 问题 1、arduino uno 驱动这款屏幕目前使的是自带的<TFT.h> 库操作…...

Flink operator实现自动扩缩容

官网文档位置&#xff1a; 1.Autoscaler | Apache Flink Kubernetes Operator 2.Configuration | Apache Flink Kubernetes Operator 1.部署K8S集群 可参照我之前的文章k8s集群搭建 2.Helm安装Flink-Operator helm repo add flink-operator-repo https://downloads.apach…...

分布式系统架构6:链路追踪

这是小卷对分布式系统架构学习的第6篇文章&#xff0c;关于链路追踪&#xff0c;之前写过traceId的相关内容&#xff1a;https://juejin.cn/post/7135611432808218661&#xff0c;不过之前写的太浅了&#xff0c;且不成系统&#xff0c;只是简单的理解&#xff0c;今天来捋一下…...

vite-plugin-imagemin安装问题

vite-plugin-imagemin 是一款图片资源压缩插件,能够在打包的时候显著的降低图片资源占用。不过,在安装过程中我们遇到了如下的问题。 对于上面的问题,有以下几种常见的解决方案: 1,使用 yarn 在 package.json 内配置(推荐) 打开 package.json 配置文件,然后添加如下脚本…...

从WWDC看苹果产品发展的规律

WWDC 是苹果公司一年一度面向全球开发者的盛会&#xff0c;其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具&#xff0c;对过去十年 WWDC 主题演讲内容进行了系统化分析&#xff0c;形成了这份…...

DAY 47

三、通道注意力 3.1 通道注意力的定义 # 新增&#xff1a;通道注意力模块&#xff08;SE模块&#xff09; class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...

拉力测试cuda pytorch 把 4070显卡拉满

import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试&#xff0c;通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小&#xff0c;增大可提高计算复杂度duration: 测试持续时间&#xff08;秒&…...

数据库分批入库

今天在工作中&#xff0c;遇到一个问题&#xff0c;就是分批查询的时候&#xff0c;由于批次过大导致出现了一些问题&#xff0c;一下是问题描述和解决方案&#xff1a; 示例&#xff1a; // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...

聊一聊接口测试的意义有哪些?

目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开&#xff0c;首…...

Java多线程实现之Thread类深度解析

Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...

分布式增量爬虫实现方案

之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面&#xff0c;避免重复抓取&#xff0c;以节省资源和时间。 在分布式环境下&#xff0c;增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路&#xff1a;将增量判…...

云原生安全实战:API网关Kong的鉴权与限流详解

&#x1f525;「炎码工坊」技术弹药已装填&#xff01; 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关&#xff08;API Gateway&#xff09; API网关是微服务架构中的核心组件&#xff0c;负责统一管理所有API的流量入口。它像一座…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

Python Einops库:深度学习中的张量操作革命

Einops&#xff08;爱因斯坦操作库&#xff09;就像给张量操作戴上了一副"语义眼镜"——让你用人类能理解的方式告诉计算机如何操作多维数组。这个基于爱因斯坦求和约定的库&#xff0c;用类似自然语言的表达式替代了晦涩的API调用&#xff0c;彻底改变了深度学习工程…...