计算机网络

计算机网络

网络分层模型

OSI7层模型

  • 应用层:为用户提供服务,例如查看用户信息
  • 表示层:做数据压缩、加密
  • 会话层:管理应用程序之间的会话
  • 传输层:数据传输
  • 网络层:IP、路由器构成的网络体系,用于定位资源最终目的地
  • 数据链路层:帧校验纠正
  • 物理层:传输比特流

image-20241021163451563

image-20240809090049967

TCP/IP网络模型

  • 应用层(应用层、表示层、会话层)
  • 传输层
  • 网络层
  • 网络接口层(数据链路层、物理层)

image-20231020185556797

交换机和网关

  • 交换机:是一种网络设备,主要用于实现局域网内的数据传输。它通过对电(光)信号进行转发,为接入交换机的任意两个网络节点提供独享的电信号通路。交换机工作在OSI参考模型的第二层(数据链路层),通常用于构建以太网并在二层网络交换中发挥重要作用。
  • 网关:是一个连接两个网络的设备,它在不同的协议之间传递数据。网关在网络间转递数据包,但主机不能转送数据包。它主要用于连接两个不同的网络,如连接PSTN网络和以太网。网关能在不同协议间移动数据,类似于传统的IP网关。

TCP协议

传输控制协议(TCPTransmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议

SYNFIN包都是主动发的

三次握手

  • C to S:SYN=1,Seq=a
  • S to C:SYN=1,ACK=1,Seq=b,Ack=a+1
  • C to S:ACK=1,Seq=a+1,Ack=b+1

参数含义:

  • SYN:(Synchronize)告诉对方我这是个连接请求!
  • ACK:表示收到!Over,Over!
  • Seq:表示当前传输的数据列
  • Ack:表示确认收到ack内容之前的内容了,请你从ack开始发给我数据

2c936a2e13b410fd3b20399f09a20610

为什么不是两次握手?

三次握手多了一个确认该连接请求是否是最新的连接请求的中间状态

而两次握手会让服务端收到客户端的SYN后立刻进入连接状态,无法判断是否是历史连接

核心原因:避免重复连接

如果客户端只需要发一次请求的功夫就能建立连接、那如果客户端刚发连接请求网络阻塞了,但因为我们是两次握手,此时服务器端就会进入已连接状态但是等不到客户端请求浪费资源不说,还可能因为客户端复活之后再发一次握手建立重复连接

避免历史连接的原理:重发的SYN和原有的是不一样的,依赖这个可以判断服务端返回的SYN是否是最新的SYN,这样就可以屏蔽旧SYN的连接请求

format,png-20230309230525514

四次挥手

  • C to S:FIN=1,ACK=1,Seq=x
  • S to C:ACK=1,Seq=y,Ack=x+1
  • waiting data transform complete………..
  • S to C:FIN=1,ACK=1,Seq=z,Ack=x+1
  • C to S:ACK=1,Seq=x+1,Ack=z+1

a1275226b7c1cf09e2f60a1b81d5c300

可以是三次挥手吗?

开启TCP延迟机制、并且没有数据发送时这样就可以把第二次和第三次合并成一个请求!

为什么是2MSL?

1、为了保证客户端发送的最后一个ACK报文段能够到达服务器。因为这个ACK有可能丢失,从而导致处在LAST-ACK状态的服务器收不到对FIN-ACK的确认报文。服务器会超时重传这个FIN-ACK,接着客户端再重传一次确认,重新启动时间等待计时器。最后客户端和服务器都能正常的关闭。假设客户端不等待2MSL,而是在发送完ACK之后直接释放关闭,一但这个ACK丢失的话,服务器就无法正常的进入关闭连接状态。

2、2个MSL中的第一个MSL是为了提供超时重传的保障,而第二MSL是在保证ACK能到达被动端的前提下,保证通信双方所有滞留在网络上的报文失效,不会影响下一次通信

流量控制

  • 作用:为了解决发送方和接收方速度不同而导致的数据丢失问题,当发送方发送的太快,接收方来不及接受就会导致数据丢失;
  • 方式:由接收端采用滑动窗口的形式,告知发送方允许/停止发包解决TCP丢包问题
    • 滑动窗口:通过接受主机响应的Window字段来限定下一个包的长度,Window字段表示的是接收主机目前可用的缓冲区大小。保障发送端速率过快,接收端从而缓冲区堆满导致的丢包现象

0292eb18c908d2588a2b531e3d235777

156e776a3df0bca467855aff2e831908

拥塞控制

作用:为了解决过多的数据注入到网络导致网络崩溃和超负荷问题;

方式:由发送方采用拥塞窗口的形式去判断网络状态,从而采取不同算法执行TCP动态发包解决网络整体质量问题

先了解两个概念:

■ 拥塞窗口(cwnd):发送方维持的一个状态变量,其大小取决于网络的拥塞程度,并且动态变化。

■ 慢开始门限(ssthresh):为了防止拥塞窗口cwnd的增长过大引起网络拥塞所设置的一个门限值。

超时重传

当发送端未收到接收端的确认消息,客户端将触发超时重传, 这就可以认定当前网络出现了拥塞。于是ssthresh调整为当前cwnd的一半,将cwnd值调整到1,重新进行慢开始

这里的确认消息是需要等到接收端向发送端发送消息时捎过去

■ 慢开始

■ 拥塞避免:逐步加一,避免增长过快

■ 超时重传(1988年TCP Tahoe版本,已废弃不用)

08b3d6a4350e3893851fdd9536859a44

缺点:

对丢包敏感,个别的TCP报文段丢失就会认为网络发生阻塞,但实际上网络并未发生阻塞。于是,发送方把cwnd陡然减小为1,并错误的开始执行慢算法,因此降低了传输效率

快重传 快恢复

快重传要求接收方收到消息后立即返回确认,当接收方收不到其他的包的时候,接收方会对收到的最近的包重复进行三次确认。发送方接收到这三次确认就会知道网络段出现了部分丢包,则此时进行快恢复

788ee923a4ee9969a4fd4bf789c666b0

快恢复是将ssthresh同样降低为cwnd的一半,cwnd=ssthresh,这样cwnd并不会从1开始执行慢开始算法。并在此时执行拥塞避免算法

快重传的三次确认机制让发送端更快地响应丢包的拥塞时间

快重传+快恢复:

对于个别丢失报文,发送方不会出现超时等待,也不会误以为出现了拥塞错误的把cwnd设置为1.实践证明,此机制可以使整个网络吞吐量增加20%

8232aaab8eefd5b29f45d0d8a3d96114

可靠传输

数据包不一致的可能原因:

TCP(传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。它设计用于通过不可靠的网络提供可靠的数据传输服务。然而,在实际应用中,TCP可能会遇到数据包不一致的问题,这些问题通常由以下几个原因造成:

  1. 网络拥塞:当网络中的数据流量超过其承载能力时,会导致数据包丢失或延迟,进而影响到TCP连接的数据一致性。
  2. 数据包丢失:在数据传输过程中,由于路由器故障、线路质量差等原因,可能导致某些数据包无法到达接收方。TCP通过序列号来检查丢失的数据包,并请求重传。
  3. 数据包乱序:在网络传输中,不同的数据包可能通过不同的路径到达目的地,这可能导致数据包到达顺序与发送顺序不同。TCP会根据每个数据包的序列号重新排序,确保数据的正确性。
  4. 数据包损坏:在传输过程中,由于各种物理因素(如电磁干扰等),数据包内容可能会发生改变。TCP使用校验和来检测这种错误,如果发现数据包损坏,则会丢弃该数据包并请求重传。
  • 面向连接:可靠的前提
  • 校验和:发送方将数据相加计算出来校验和,填补到TCP头部,接受方对数据校验和重新计算,对比TCP头部校验和,如果相等则数据正确

该方法可以校验数据在传输中,因为电磁干扰等问题导致的数据包损坏的问题

46db3a77b5e13c9b86c9dc98e8271c3e

  • 超时重传机制:ACK序列号检测丢包

dddd2abd81104eac354a76bfc2e0269e

  • 拥塞控制:控制流量减少阻塞

HTTP

HTTP字段

  1. Host 字段

客户端发送请求时,用来指定服务器的域名。

img

1
Host: www.A.com

有了 Host 字段,就可以将请求发往「同一台」服务器上的不同网站。

  1. Content-Length 字段

服务器在返回数据时,会有 Content-Length 字段,表明本次回应的数据长度。

img

1
Content-Length: 1000

如上面则是告诉浏览器,本次服务器回应的数据长度是 1000 个字节,后面的字节就属于下一个回应了。

大家应该都知道 HTTP 是基于 TCP 传输协议进行通信的,而使用了 TCP 传输协议,就会存在一个“粘包”的问题,HTTP 协议通过设置回车符、换行符作为 HTTP header 的边界,通过 Content-Length 字段作为 HTTP body 的边界,这两个方式都是为了解决“粘包”的问题。具体什么是 TCP 粘包,可以看这篇文章:如何理解是 TCP 面向字节流协议?(opens new window)

  1. Connection 字段

Connection 字段最常用于客户端要求服务器使用「HTTP 长连接」机制,以便其他请求复用。

img

HTTP 长连接的特点是,只要任意一端没有明确提出断开连接,则保持 TCP 连接状态。

HTTP 长连接

HTTP/1.1 版本的默认连接都是长连接,但为了兼容老版本的 HTTP,需要指定 Connection 首部字段的值为 Keep-Alive

1
Connection: Keep-Alive

开启了 HTTP Keep-Alive 机制后, 连接就不会中断,而是保持连接。当客户端发送另一个请求时,它会使用同一个连接,一直持续到客户端或服务器端提出断开连接。

PS:大家不要把 HTTP Keep-Alive 和 TCP Keepalive 搞混了,这两个虽然长的像,但是不是一个东西,具体可以看我这篇文章:TCP Keepalive 和 HTTP Keep-Alive 是一个东西吗?(opens new window)

  1. Content-Type 字段

Content-Type 字段用于服务器回应时,告诉客户端,本次数据是什么格式。

img

1
Content-Type: text/html; Charset=utf-8

上面的类型表明,发送的是网页,而且编码是UTF-8。

客户端请求的时候,可以使用 Accept 字段声明自己可以接受哪些数据格式。

1
Accept: */*

上面代码中,客户端声明自己可以接受任何格式的数据。

  1. Content-Encoding 字段

Content-Encoding 字段说明数据的压缩方法。表示服务器返回的数据使用了什么压缩格式

img

1
Content-Encoding: gzip

上面表示服务器返回的数据采用了 gzip 方式压缩,告知客户端需要用此方式解压。

客户端在请求时,用 Accept-Encoding 字段说明自己可以接受哪些压缩方法。

1
Accept-Encoding: gzip, deflate

GET 与 POST

不能说GET比POST安全,因为他们的参数都可以通过报文看到!

Get和POST其实是RFC的定义规范,所以一个请求无论是否是GET也能在请求体携带参数

HTTP版本对比

HTTP 1.0

缺乏长连接、和管道支持每个对象都需要单独的TCP连接

  • 状态管理:HTTP 1.0缺乏持久连接,这意味着每次请求都需要建立一个新的TCP连接,这增加了网络开销。
  • 缓存处理:HTTP 1.0提供了简单的缓存验证机制,但没有明确的过期规则或缓存协调。
  • 性能限制:由于缺乏管道化支持,每个对象都需要单独的TCP连接,这在多对象页面上表现不佳。

HTTP 1.1

长连接、多请求同时发送无需等待响应、压缩请求体内容;缺点是头部未压缩

管道解决了请求的队头阻塞,但是没有解决响应的队头阻塞

17-管道网络传输

  • 持久连接:HTTP 1.1默认启用了持久连接,并引入了流水线处理,允许多个请求同时发送而无需等待响应。
  • 缓存改进:提供了更复杂的缓存处理规则,包括条件请求和更强的缓存一致性。
  • 带宽优化:通过允许Body使用编码压缩来减少带宽消耗。

缺点

  • 请求 / 响应头部(Header)未经压缩就发送,首部信息越多延迟越大。只能压缩 Body 的部分;
  • 发送冗长的首部。每次互相发送相同的首部造成的浪费较多;

HTTP 2.0

并发传输、头部压缩、服务推送、二进制格式(解析效率、可靠性)

  • 多路复用:HTTP/2通过单一的TCP连接支持多个并行操作,而不是为每个请求建立单独的连接。
  • 头部压缩:HTTP/2使用HPACK算法对头部进行压缩,减少了头部信息传输的开销。
  • 服务端推送:服务器可以预测客户端可能需要的资源并提前发送,减少了延迟。
  • 二进制格式:HTTP/2使用二进制而非文本格式,提高了协议解析效率和可靠性。

HTTP 3.0

基于QUIC减少延迟

  • 基于QUIC:HTTP/3基于UDP之上的QUIC协议,而不是像之前的版本那样基于TCP。QUIC提供了类似TCP的功能,但是减少了握手延迟,提高了恢复速度。
  • 连接迁移:QUIC支持无缝连接迁移,比如当设备在网络间切换时不会断开连接。
  • 降低延迟:QUIC减少了往返时间(RTT),特别是在移动设备和高延迟网络环境中。
  • 加密:QUIC默认使用TLS加密,提供了更好的安全性。

HTTP1.0和HTTP1.1

HTTP/1.1 相比 HTTP/1.0 性能上的改进:

  • 使用长连接的方式改善了 HTTP/1.0 短连接造成的性能开销。
  • 支持管道(pipeline)网络传输,只要第一个请求发出去了,不必等其回来,就可以发第二个请求出去,可以减少整体的响应时间。

但 HTTP/1.1 还是有性能瓶颈:

  • 请求 / 响应头部(Header)未经压缩就发送,首部信息越多延迟越大。只能压缩 Body 的部分;
  • 发送冗长的首部。每次互相发送相同的首部造成的浪费较多;
  • 服务器是按请求的顺序响应的,如果服务器响应慢,会招致客户端一直请求不到数据,也就是队头阻塞
  • 没有请求优先级控制;
  • 请求只能从客户端开始,服务器只能被动响应。

HTTP2

HTTP/2 协议是基于 HTTPS 的,所以 HTTP/2 的安全性也是有保障的。

HTT/1 ~ HTTP/2

那 HTTP/2 相比 HTTP/1.1 性能上的改进:

  • 头部压缩(HPack将请求头记录为索引号)
  • 二进制格式(增加传输效率,压缩传输体积)
  • 并发传输(Stream技术)

针对不同的 HTTP 请求用独一无二的 Stream ID 来区分,接收端可以通过 Stream ID 有序组装成 HTTP 消息,不同 Stream 的帧是可以乱序发送的,因此可以并发不同的 Stream ,也就是 HTTP/2 可以并行交错地发送请求和响应

HTTP/2 虽然通过多个请求复用一个 TCP 连接解决了 HTTP 的队头阻塞 ,但是一旦发生丢包,就会阻塞住所有的 HTTP 请求,这属于 TCP 层队头阻塞

  • 服务器主动推送资源

HTTP/3 做了哪些优化?

HTTP3使用UDP 发送是不管顺序,也不管丢包的,所以不会出现像 HTTP/2 队头阻塞的问题。大家都知道 UDP 是不可靠传输的,但基于 UDP 的 QUIC 协议 可以实现类似 TCP 的可靠性传输。

QUIC 有以下 3 个特点。

  • 无队头阻塞
  • 更快的连接建立
  • 连接迁移

HTTP 缓存技术

HTTP 缓存实现方式

  1. 强制缓存

多次请求数据一样就会在本地建立缓存,并设置过期时间

  1. 协商缓存

一个请求已经访问过一次了,下次访问请求缓存,如果已经过期,则携带etag向服务器请求数据,比对etag是否相同,如果相同返回304,并将缓存数据返回:在这里etag类似于版本号!

对于一些具有重复性的 HTTP 请求,比如每次请求得到的数据都一样的,我们可以把这对「请求-响应」的数据都缓存在本地,那么下次就直接读取本地的数据,不必在通过网络获取服务器的响应了,这样的话 HTTP/1.1 的性能肯定肉眼可见的提升。

所以,避免发送 HTTP 请求的方法就是通过缓存技术,HTTP 设计者早在之前就考虑到了这点,因此 HTTP 协议的头部有不少是针对缓存的字段。

HTTP 缓存有两种实现方式,分别是强制缓存和协商缓存

什么是强制缓存?

对应的请求产生在浏览器的缓存没有过期,浏览器强制使用该缓存

强缓存指的是只要浏览器判断缓存没有过期,则直接使用浏览器的本地缓存,决定是否使用缓存的主动性在于浏览器这边。

如下图中,返回的是 200 状态码,但在 size 项中标识的是 from disk cache,就是使用了强制缓存。

强缓存是利用下面这两个 HTTP 响应头部(Response Header)字段实现的,它们都用来表示资源在客户端缓存的有效期:

  • Cache-Control, 是一个相对时间;
  • Expires,是一个绝对时间;

如果 HTTP 响应头部同时有 Cache-Control 和 Expires 字段的话,Cache-Control 的优先级高于 Expires

Cache-control 选项更多一些,设置更加精细,所以建议使用 Cache-Control 来实现强缓存。具体的实现流程如下:

  • 当浏览器第一次请求访问服务器资源时,服务器会在返回这个资源的同时,在 Response 头部加上 Cache-Control,Cache-Control 中设置了过期时间大小;
  • 浏览器再次请求访问服务器中的该资源时,会先通过请求资源的时间与 Cache-Control 中设置的过期时间大小,来计算出该资源是否过期,如果没有,则使用该缓存,否则重新请求服务器;
  • 服务器再次收到请求后,会再次更新 Response 头部的 Cache-Control。

什么是协商缓存?

协商缓存就是与服务端协商之后,通过协商结果来判断是否使用本地缓存

发现本地缓存过期了,向服务器协商是否过期缓存可以使用,如果可以使用则直接返回本地缓存的数据

当我们在浏览器使用开发者工具的时候,你可能会看到过某些请求的响应码是 304,这个是告诉浏览器可以使用本地缓存的资源,通常这种通过服务端告知客户端是否可以使用缓存的方式被称为协商缓存。

上图就是一个协商缓存的过程,所以协商缓存就是与服务端协商之后,通过协商结果来判断是否使用本地缓存

注意,协商缓存这两个字段都需要配合强制缓存中 Cache-Control 字段来使用,只有在未能命中强制缓存的时候,才能发起带有协商缓存字段的请求

下图是强制缓存和协商缓存的工作流程:

当使用 ETag 字段实现的协商缓存的过程:

  • 当浏览器第一次请求访问服务器资源时,服务器会在返回这个资源的同时,在 Response 头部加上 ETag 唯一标识,这个唯一标识的值是根据当前请求的资源生成的;

  • 当浏览器再次请求访问服务器中的该资源时,首先会先检查强制缓存是否过期:

    • 如果没有过期,则直接使用本地缓存;
    • 如果缓存过期了,会在 Request 头部加上 If-None-Match 字段,该字段的值就是 ETag 唯一标识;
  • 服务器再次收到请求后,

    会根据请求中的 If-None-Match 值与当前请求的资源生成的唯一标识进行比较

    • 如果值相等,则返回 304 Not Modified,不会返回资源
    • 如果不相等,则返回 200 状态码和返回资源,并在 Response 头部加上新的 ETag 唯一标识;
  • 如果浏览器收到 304 的请求响应状态码,则会从本地缓存中加载资源,否则更新资源。

http与https

不同点

  • http和https使用的端口分别为80,443
  • https为加密传输
  • https需要向CA(证书权威机构)申请数字证书,来保证服务器的身份是可信的

HTTPS 在 HTTP 与 TCP 层之间加入了 SSL/TLS 协议,可以很好的解决了上述的风险:

  • 信息加密:交互信息无法被窃取,交互信息由明文转变为密文
  • 校验机制:无法篡改通信内容,保证你看到的都是服务器提供的安全的信息
  • 身份证书:证明淘宝是真的淘宝网,证明网站的正规

https是如何实现的呢?

HTTPS 是如何解决上面的三个风险的?

  • 混合加密的方式实现信息的机密性,解决了窃听的风险。
  • 摘要算法的方式来实现完整性,它能够为数据生成独一无二的「指纹」,指纹用于校验数据的完整性,解决了篡改的风险。
  • 将服务器公钥放入到数字证书中,解决了冒充的风险。
  1. 混合加密
  1. 客户端发送支持的(非)加密套件列表,并传递浏览器随机数(这里的浏览器随机数是用来最后生成公钥使用的)
  2. 服务端返回对应的加密套件,并把服务端的随机数、公钥返回给客户端
  3. 最后客户端生成pre-master给服务端,服务端使用私钥解密,这时两方同时具备这三个随机数,生成共同的公钥
  4. 共同公钥用于非对称加密!

image-20240329204138506

  1. 摘要算法

保障数据不被篡改:

简单来说就是在发送内容的时候计算出原内容的Hash值,送到服务端继续计算Hash值比对,但是并不能保证「内容 + 哈希值」不会被中间人替换,因为这里缺少对客户端收到的消息是否来源于服务端的证明

  1. 数字证书

数字证书是由内容做完Hash运算得到的Hash值,再使用私钥对其加密得到数字签名:

私钥是只有服务器有的,对应的公钥才能解密,确保解决了冒充风险!

通过数字证书的方式保证服务器公钥的身份,解决冒充的风险

网络层

UDP

  • 无连接:只知道对端的IP和端口号就可以发送,不需要实现建立连接。(就像寄信)。
  • 不可靠:没有确认机制, 没有重传机制。如果因为网络故障该段无法发到对方, UDP协议层也不会给应用层返回任何错误信息。
  • 面向数据报: 应用层交给UDP多长的报文, UDP原样发送既不会拆分,也不会合并。所以UDP不能够灵活的控制读写数据的次数和数量。
    UDP存在接收缓冲区,但不存在发送缓冲区。UDP没有发送缓冲区,在调用send to时会直接将数据交给内核,由内核将数据传给网络层协议进行后续的传输动作。UDP具有接收缓冲区,但是这个接收缓冲区不能保证收到的UDP报文的顺序和发送UDP报的顺序一致,如果缓冲区满了再到达的UDP数据报就会被丢弃。

为什么UDP不需要发送缓冲区? 因为UDP不保证可靠性,它没有重传机制,当报文丢失时,UDP不需要重新发送,而TCP不同,他必须具备发送缓冲区,当报文丢失时,TCP必须保证重新发送,用户不会管,所以必须要具备发送缓冲区。

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

TCP

  • 面向连接:TCP要求建立连接(三次握手),并在数据传输完成后断开连接(四次挥手)
  • 可靠性:重传机制,错误检测(如果检测到错误,数据包将被丢弃,发送方会在超时后重新发送丢失的数据包)
  • 多路复用:TCP支持在同一连接上进行多个数据流的传输
  • 流量控制:TCP使用滑动窗口机制来进行流量控制,防止发送方发送数据的速度超过接收方处理的能力

ARP

  • 定义:ARP为地址解析协议(Address Resolution Protocol,介于网络层和数据链路层之间用于转换,将IP地址转化为设备的MAC地址
  • 特点:广播问询,单播响应
  • 工作流程:当局域网内主机A需要向另外一个主机B发送IP数据包,在网络层已经知道主机B的IP,查询本机维护的IP-MAC-TTL的ARP表查看是否能直接找到主机B地址,如果找不到则会发送广播数据包,包含了需要得到对应MAC的IP地址,这时候局域网内所有的主机都会判断这个IP地址是否是自己,如果不是则丢弃,如果是则发送一个响应数据包带上自己的MAC地址,维护一张ARP表保存A的IP与Mac映射,发送到主机A,主机A也会维护一张ARP表保存B的IP与Mac映射;最后进行物理寻址

image-20240809090404681

NAT

NAT(网络地址转换:Network Address Translation)允许多台设备共享一个IP地址访问互联网

作用是将局域网IP转换为公网IP!

  • 减少公网IP地址的分配
  • 保障内部网络隐私和安全

粘包问题

什么是粘包问题

主要关于数据的定界问题

  1. UPD:面向报文协议

当用户消息通过 UDP 协议传输时,操作系统不会对消息进行拆分,在组装好 UDP 头部后就交给网络层来处理,所以发出去的 UDP 报文中的数据部分就是完整的用户消息,也就是每个 UDP 报文就是一个用户消息的边界,这样接收方在接收到 UDP 报文后,读一个 UDP 报文就能读取到完整的用户消息。

  1. TCP:面向字节流的协议

[Hi] [I am student!]发送这两条消息时可能会被拆开发送,所以就需要定界

当用户消息通过 TCP 协议传输时,消息可能会被操作系统分组成多个的 TCP 报文,也就是一个完整的用户消息被拆分成多个 TCP 报文进行传输。

如何解决粘包

固定长度的消息

这种是最简单方法,即每个用户消息都是固定长度的,比如规定一个消息的长度是 64 个字节,当接收方接满 64 个字节,就认为这个内容是一个完整且有效的消息。

但是这种方式灵活性不高,实际中很少用。

特殊字符作为边界

我们可以在两个用户消息之间插入一个特殊的字符串,这样接收方在接收数据时,读到了这个特殊字符,就把认为已经读完一个完整的消息。

HTTP 是一个非常好的例子。

a49a6bb8cd38ae1738d9c00aec68b444

HTTP 通过设置回车符、换行符作为 HTTP 报文协议的边界。

有一点要注意,这个作为边界点的特殊字符,如果刚好消息内容里有这个特殊字符,我们要对这个字符转义,避免被接收方当作消息的边界点而解析到无效的数据。

自定义消息结构

我们可以自定义一个消息结构,由包头和数据组成,其中包头包是固定大小的,而且包头里有一个字段来说明紧随其后的数据有多大

比如这个消息结构体,首先 4 个字节大小的变量来表示数据长度,真正的数据则在后面。

1
2
3
4
struct { 
u_int32_t message_length;
char message_data[];
} message;

当接收方接收到包头的大小(比如 4 个字节)后,就解析包头的内容,于是就可以知道数据的长度,然后接下来就继续读取数据,直到读满数据的长度,就可以组装成一个完整到用户消息来处理了。

总结

  • 对于定长的数据包,保证每次都按固定的大小读取即可;
  • 对于变长的包,可在包头的位置,约定一个包总长度的字段,从而就知道了包的结束位置;
  • 对于变长的包,还可以在包和包之间使用明确的分隔符(应用层协议,是我们自己写的,只要保证分隔符不和正文冲突即可)

思考

国内访问国外网站这个过程发生了什么?

  1. 发起请求:
    • 用户在国内的电脑或移动设备上输入网址或发起访问请求。
  2. 域名解析(DNS查询):
    • 用户的设备会向配置的DNS服务器发送一个查询包,询问该网址对应的IP地址。
    • DNS服务器会返回对应的IP地址给用户的设备。
  3. 数据包传输至ISP:
    • 用户的设备通过网络接入设备(如路由器)将请求数据包发送到本地网络提供商(ISP)。
  4. 转发至国际出口节点:
    • ISP将请求数据包转发到国家本地的边界网关(也称为国际出口节点),这是连接国内网络和国际互联网的关键节点。
  5. 选择最佳国际出口通道:(VPN)
    • 边界网关会根据目标国际IP地址来选择最佳的国际出口通道或运营商,并将请求数据包发送到该出口通道。
  6. 数据包进入国际互联网:
    • 请求数据包从国内网络通过国际出口通道进入国际互联网,然后经过一系列的路由器和网络节点进行传输。
  7. 到达目标国家:
    • 当请求数据包到达目标国家之后,它会经过该国家的边界网关,然后进入目标国家的本地网络。
  8. 目标服务器响应:
    • 目标国家的本地ISP会将请求数据包传送给目标外网服务器。
    • 目标外网服务器接收到请求数据包后,会将响应数据包通过相同的路径返回给用户的设备。
  9. 数据包返回用户设备:
    • 响应数据包沿着相同的路径通过边界网关、国际出口通道和ISP传回至用户的设备。
  10. 解析并显示内容:
    • 用户的设备接收到响应数据包后,解析其中的内容。如果是网页,设备会渲染并显示给用户;如果是邮件,则会在客户端上显示。

![【干货】你还不知道路由器工作原理吗,99%的人都看得懂 - 图片](../image/【干货】你还不知道路由器工作原理吗,99%的人都看得懂 - 图片.png)

TCP和UDP的区别

  • TCP:面向连接、可靠(重传机制)、基于字节流
  • UDP:无连接、不可靠、大小受限(64kb)、基于数据报

UDP不存在发送缓冲区注定他没有重传机制,但是他有接收缓冲区,这个缓冲区不保障数据的顺序、超过大小的数据也会被丢弃

DDOS攻击

分布式拒绝服务攻击,与Dos区别在于DDOS采用的是分布式攻击,而DOS单一机器的攻击

image-20241130170352104

攻击方法:

  • TCP洪水:将多台服务器向同一台服务器同时发送TCP连接请求,但是不进行最后的第三次握手,导致服务器接收到大量的资源进入半连接的状态
  • 高频的Http请求:导致每个请求都要访问数据库,这种费事的IO操作在高频的执行下也会将服务器弄垮

解决策略:

  • 使用缓存
  • 设置访问黑名单
  • 微服务架构,负载均衡

拓展:

UDP-NTP实现DDOS攻击

  • UDP找出网络中支持NTP的主机
  • 通过NTP对流量进行增大传输