阅读 933

(建议精读)一文夯实你的网络基础

知识体系

应用层

关于应用层,最常见的面试莫过于HTTP、DNS两大块。

HTTP

001. 报文结构

HTTP可以分为请求报文和响应报文两个部分:

请求报文

  1. 请求行: 方法(具体请查看下方的请求方法) + 路径 + http版本。
GET https://fonts.googleapis.com/css?family=Google%20Sans%3A400 HTTP/1.1
复制代码
  1. 请求头

3. 请求内容

响应报文

  1. 状态行: 由http版本、状态码和原因三部分组成。
HTTP/1.1 200 OK
复制代码
  1. 响应头

3. 响应内容

请求头和响应头、请求内容和响应内容这两个数据对书写形式上都是保持一致的,内容上都是对于数据实体的保存,而头的数据有几项可以关注,与写脚本时息息相关。 随便拿一个案例作为案例,编写一个脚本时,往往需要自定义一个header,而这个header的定义不可以或缺的几项:

  1. user-agent:这个字段指定的是最后使用的浏览器是什么
  2. accept-encoding:支持的编码类型,如果服务器的数据格式并不存在于此列,将返回406 的响应码
  3. cookie:这个数据往往与用户行为相关,数据保存可以实现自动登陆等能力。

002. 请求方法

  • Get: 请求获取资源
  • Post: 在资源后附加新的数据
  • Put: 请求服务器存储一个资源
  • Delete: 请求服务器删除资源
  • Head: 请求获取资源的响应消息报头
  • Options: 请求查询服务器的性能,或者查询与资源相关的选项和需求

GET与POST方法之间的差异

  1. 数据长度方面: Get 作为数据传输时后跟请求参数的长度是受限的,所以需要传送大量数据的时候,也不适合使用Get 方式。Post 没有这种限制。
  2. 数据显示: Get 是显式传输,在地址栏中清楚的看到,这种方式不适合传送私密数据。Post会做隐藏。
  3. 数据传递方面: Get请求是将Header 和Data 一次性进行传递,而Post 分为两个步骤会先传递Header,后传递Data。从表现上来看Get 请求只会返回200 响应码,而Post 会先返回100 响应码,再返回200 响应码。(Firefox是个特例)另外Get方法只能通过ASCII 码进行传输,Post 没有此类限制。
  4. 数据缓存方面: 通过Get 发出的请求浏览器主动会留一份缓存,而Post 不会。

003. 响应码

响应状态码可以分为以下5类:

  • 1xx: 指示信息--表示请求已接收,继续处理。
  • 2xx: 成功--表示请求已被成功接收、理解、接受。
  • 3xx: 重定向--要完成请求必须进行更进一步的操作。
  • 4xx: 客户端错误--请求有语法错误或请求无法实现。
  • 5xx: 服务器端错误--服务器未能实现合法的请求。

常见状态代码及状态描述的说明如下:

1XX

100 Continue: 服务器已收到初始请求,现正在等待接收其余部分。

101 Switching Protocols: 请求者已要求服务器切换协议,服务器已确认并准备进行切换。

2XX

200 OK: 客户端请求成功。

204 No Content: 未返回任何内容,浏览器应该继续显示原来的文档。

206 Partial Content: 使用Content-Range进行断点续传时会出现。

3XX

304 Not Modified: 服务器数据并没有发生过更新,可以使用本地缓存。

305 Use Proxy: 只能使用代理访问请求的网页。如果服务器返回此响应,那么,服务器还会指明请求者应当使用的代理。

4XX

400 Bad Request: 客户端请求有语法错误,不能被服务器所理解。

401 Unauthorized: 请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用。

403 Forbidden: 服务器拒绝提供服务。

404 Not Found: 服务器上并不存在对应的资源文件。

405 Method Not Allowed: 请求方法(GETPOSTHEADDELETEPUTTRACE等)禁用。

406 Not Acceptable: 已找到指定资源,但是数据的格式与Accpet中存在出入。

413 Request Entity Too Large: 请求实体过大,已超出服务器的处理能力。如果服务器认为自己能够稍后再处理该请求,则应该提供一个Retry-After头。

5XX

500 Internal Server Error: 服务器内部发生了错误。

501 Not Implemented: 服务器不具备完成请求的功能

503 Server Unavailable: 服务器当前不能处理客户端的请求,一段时间后可能恢复正常。可能的原因有超载、服务打挂等。

以上罗略是我认为比较重要的部分,响应码还有非常之多,网上也大有文章在,这里不做更多的罗列。响应码集合跳转链接

005. Version 1.0, 1.1, 2.0, 3.0

从HTTP诞生至今也已经迭代了非常久的时间了,而其优化围绕的主题一直都是带宽和时延。最近逐渐火热起来的HTTP/3 也渐渐走入大家的视野,但是完全推广开想来还是需要经过一个比较冗长的时间验证。这次主要还是探讨各个版本之间的升级都是怎么样的。

Version 1.0 -> 1.1

Version 1.1版本升级的三大亮点:长连接、Range的引入以及Host头处理。

  1. Range字段的引入: 如果客户端只希望要某个数据实体的部分, HTTP1.0的协议下服务端的返回数据还是整个数据实体,这样的数据量对于客户端而言是无用的,对于网络而言加大了负荷。而Range字段的引入能够很好的解决这个问题。
  2. 长连接: HTTP的无状态协议,每次请求都是独立开来的。在Version 1.0时,每次数据传输都要创建一个TCP连接,中间存在大量的连接耗时,而长连接只用创建一次连接就能够解决需要多次数据传输的问题,有效的减少了新连接创建的成本。对应标签 Connection: keep-alive
  3. Host头处理: Version 1.0时默认每台服务器仅与一个IP地址绑定,但是虚拟机的存在打破了这个前置条件,所以Version 1.1之后如果没有处理,将会返回响应码400 Bad Request。

Version 1.1 -> 2.0

Version 2.0版本升级的三大亮点:header压缩、服务端推送、多路复用

  1. header压缩: HPACK维护了静态和动态索引表两份索引表。动态索引表因针对同一次连接生效,静态索引表一份固化数据,如下图所示:

当请求中出现静态索引表的中内容时,就会以数值直接替换,减少占用空间。

更多细节内容可以查看文章详解http-2头部压缩算法

  1. 服务器推送: 服务器可以主动向客户端推送某些数据,当客户端需要时可以直接在本地缓存中进行获取。
  2. 多路复用: 归根结底就是一个并行传输的概念,在Version 1.0下的传输是串行的,影响了数据传输的效率。

Version 2.0 -> 3.0

从往期的HTTP 结构模型看,在运输层终究还是使用TCP来保障数据的可靠传输,但是HTTP/3 中将底层的换成了UDP,并引入了一种名为QUIC 的协议。这样的改造自然有利有弊。UDP 的包头小,且不需要建立握手和挥手的操作,从本质上节省了空间和时间。 但是UDP 是一种不可靠的数据传输,纵观其他协议内部并不存在可靠传输的保障和网络流量保障,这项重要的任务自然而然就落在了QUIC 协议上。(关于这些TCP重要特性可以查看下方的内容)

如果希望对QUIC 协议有更多的了解,可以查看文章:技术扫盲:新一代基于UDP的低延时网络传输层协议——QUIC详解

006. HTTP 和 HTTPS

HTTPS = HTTP + SSL/TLS,关于原理部分请查看:SSL/TLS的实现原理

这个小节能力使用最后的体现就是HTTPHTTPS两者之间的差别 —— 数据加密,通过wireshark软件对数据的一个抓包。(Android开发中使用到的抓包软件有Charles、ProxyMan,个人更倾向于后者

加密前加密后

从展现的数据能够发现,如果我们数据里掺杂了我们的个人信息,比如说账号密码等等,明文传输下被抓去之后,造成的结果就是灾难性的。而这就是https做了安全性处理带来的好处。害处自然也是存在的,就是需要加密和解密的时间(SSL时间),但是这个削弱程度已经完全的被现代社会的高速处理能力给弱化了。

007. Cookie

HTTP作为无状态的协议不会记录用户的各种状态,每次的HTTP 请求都是都是独立开来的,那做到类似下一次进入网站时保持登陆状态的操作仅靠HTTP 的连接是不够的,这也就引入了Cookie的这样。

Cookie本质上知识存储在客户端的小型文本文件,其数据格式是以键值对的形式存在。以掘金为例:

名称为Key,内容为Value,域名和路径决定了作用域。

Cookie的工作流程

从图中能够看出,Cookie是由服务器所产生,而后又被客户端在本地进行保存的数据。而这份数据的会在下次HTTP 请求发出时携带。其表现形式如下:

# 响应行
Set-cookie: 1678
# 请求行
cookie: 1678
复制代码

Cookie的属性

生存周期

Cookie 的有效期如下的两个两个属性进行控制:

  • Expires:过期时间
  • Max-Age:从浏览器收到报文开始到过期的时间间隔,单位:秒。
作用域

作用域同样存在两个属性: 域名(Domain)和路径(Path)。如果路径为/。则表示域名下的任意路径都允许使用这个 Cookie。

008. Web缓存

Web缓存,也可以叫做代理服务器,主要能力是保存最近请求过的对象副本。

为什么Web中需要引入这样的概念? 以在浏览器中键入www.google.com到完成数据获取为例,在没有Web缓存的情况下,这个过程中浏览器需要先和目标服务器建立TCP 连接,然后发送对该对象的HTTP 请求,得到服务器响应后就能够完成显示。

但如果这个数据是经常要被获取的,并且它的体积非常庞大呢? 在这种情况下,大量的客户端会对服务器发出请求,导致服务器压力过大,且会有大量的重复流量出现在网络中。这也就有了Web缓存的诞生,通过缓存的能力,在数据不发生改变的情况下能够大大减少网络中的重复流量。

Web缓存的运作流程

有了Web缓存以后,可以划分出两类工作流程:有缓存和无缓存。 而不论是哪种流程下,都会先经过Web缓存服务器。

  1. 在无缓存的情况下,就和平常一般与服务器发起HTTP 请求获取数据,但这个数据获取完成之后,Web服务器会在本地存储这次的数据副本,下次再发生数据请求时就走有缓存的路径。
  2. 有无缓存的情况下,就如下图流程一般,需要注意有以下几点内容:
    • 响应码: 如图中所以服务器会做出决策,如果本地数据可用,服务器会返回304 Not Midified 响应码,反之200 Success,更新本地数据。
    • 数据过期: Cache-Control字段的使用,打开一些网站用开发者工具往Request请求里找一下就能找到。这直接会影响当前数据的是否需要重新再向远端服务器重新进行获取。它是以秒为单位计算的,如果只有private说明当前数据只有一次有效。

DNS

在DNS这个模块上,考察的点一般都是工作流程的问题,所以重点做一个讲解。

Q1:首先要知道DNS是干什么的?

官方语言是将域名地址转化为IP地址,那俗话讲就是将 www.baidu.com 转化为 14.215.177.39。玩过云服务器的朋友应该知道,不管是哪家公司给你的公网地址都是一个IP地址,而想要域名的话,就要自己再购买后,然后绑定完成。

Q2:那为什么不直接用IP地址来访问呢?

这个问题其实有挺多原因的:

  1. 好记。 生硬的数字,没有他的实际意义,如果我告诉他的IP地址和域名地址,你会记住哪个?这显然是域名地址。
  2. 分布式中的应用。 一个域名地址可以对应多个IP地址,而通过域名方式请求,以某种算法匹配到某个特定的IP也就做到了负载均衡。

001. 实现流程

一般来说这种事件的发起人是我们的本地客户机,通过浏览器输入了www.baidu.com ,那么这个时候他的探索历程开始了。

  1. 先搜索本地的hosts文件,这里可以比较清楚的看到一些IP地址对应的域名地址 (命令为:sudo vim /etc/hosts)

  1. 如果本地不存在,先向本地域名服务器(DNS缓存)发出请求为什么要设置本地域名服务器?)。

  2. 这里需要注意,他是直接向根DNS服务器发出请求,如果根DNS服务器中,我们同样的还是找不到,那我们才有开始下面的步骤,向下级服务器发出查找请求。

  1. 下级服务器不断向下查询,直到找到了对应的IP地址后,就将我们的数据进行一个返回,自此我们就得到了我们我们需要的IP地址。

002. 为什么需要一个本地域名服务器(DNS缓存)?

和Web缓存的思想整体类似,如果直接从根域名服务器开始查询,整体的查询耗时就会增大,而且网络中无端多出大量的DNS查询流量,本地域名服务器的存在其实就是一种空间换时间的思想。(之后如果有提到本地的一些东西,从大角度上保持空间换时间即可

其他

001. P2P体系下的运作流程(以BitTorrent为例)

常见的网络体系有两种:B/S体系;P2P体系。 上文中提到的HTTP 就是B/S 体系下的常客,而P2P体系呢?其实在生活中有一个非常好的案例,迅雷!!

在P2P体系下有一个非常大的特点,如果一个资源经常被大家下载时,这个资源下载就贼快,而冷门资源下载速度可能就贼慢。

在P2P的体系下存在几个重要的名次:洪流、追踪器以及对等方。

  1. 洪流: 下载同一个文件的客户端集合。
  2. 追踪器: 用于追踪所有尚存在的客户端,做生命周期的维护。
  3. 对等方: 下载资源的客户端。

现在比较火的《送你一朵小红花》的盗版资源被放在被了某个资源网上,希望观看的用户便会疯狂进去下载。在P2P的体系下,这些下载用户就进入了一条洪流中,并且他们会向追踪器注册自己。当你同样想下载这份资源时,你也会进入洪流中,重复操作。此时追踪器会将一定数量的子集返还给你用于你的资源获取。假设现在你缺少这个资源的第5块,便向这个子集中发出申请。而如果全部都没有就只能向服务器发出请求获取。如此下来凑齐全部的数据块。

这也是P2P体系下载速率高的根本原因,如果对等方越多,数据的请求效率往往越高。

002. 邮件系统

邮件系统有三大组成部分:用户代理、邮件服务器和简单邮件传输协议。

用户代理使得用户能够完成阅读、撰写、保存等等一系列能力,而其最为显著的表现形式就是邮箱系统。

Apple Mail网易邮箱大师

邮件系统的基本运作流程

用户通过用户代理即网易邮箱进行报文撰写,完成以后发送一个qq邮箱,这时用户代理会将数据发送给发送方的邮件服务器,比如我用的是163邮箱,那发给的就是163的邮件服务器,而接收方使用的是qq邮箱,那邮件服务器就会与qq对应qq邮箱的邮件服务器连接,然后将数据发送过去,当接收方需要查看时,接收方的用户代理就会从qq的邮件服务器去获取数据,就能看到发送方发送的信息了。

其中邮件服务器之间采用简单邮件协议(SMTP)进行沟通,这种沟通协议仅支持7比特的ASCII,且不使用中间邮件服务器。

用户代理与邮件服务器之间的数据传递有多种协议可以使用,POP3、HTTP等等。

传输层

UDP

001. 报文结构

从图中可以看出有如下的组成部分:

  • 源端口号
  • 目的端口号
  • 长度
  • 校验和: 提供差错检测能力。
  • 应用数据(报文): 承载数据实体。

模拟UDP 数据传输代码:

# UDPServer
from socket import *

serverName = "127.0.0.1"
serverPort = 1200
serverSocket = socket(AF_INET, SOCK_DGRAM)
serverSocket.bind((serverName, serverPort))
while True:
    message, clientAddress = serverSocket.recvfrom(2048)
    modifiedMessage = message.upper()
    serverSocket.sendto(modifiedMessage, clientAddress)
    
# UDPClient
from socket import *

serverName = "127.0.0.1"
serverPort = 1200
clientSocket = socket(AF_INET, SOCK_DGRAM)
message = "Input lowercase sentence:".encode()
clientSocket.sendto(message, (serverName, serverPort))
modifiedMessage, serverAddress = clientSocket.recvfrom(2048)
print(modifiedMessage.decode())
clientSocket.close()
复制代码

002. 为什么会有应用选择使用UDP作为传输层协议?

选择UDP作为传输层协议首先必须知道其优缺点是什么:

  1. 无需连接建立: 相较于TCP 省去了握手及挥手的时间。
  2. 分组开销小: 可以和之后TCP 中的报文结构比较,UDP 的报文段只需8字节,TCP 需要20字节。
  3. 无连接状态: TCP 中会维护各种状态以实现能力,而这些能力实现的前提是连接状态的维护。UDP 仅存在校验和,而校验和的存在仅影响数据是否需要重传。
  4. 数据实时传递: TCP会因为拥塞控制等问题,控制输入网络的流量大小,UDP是拿到就传。
  5. 数据可能丢失: UDP本身不做可靠传输处理,所以最后出现数据丢失也是一种非常常见的现象。

根据以上的优缺点罗列,可以知道对应的App应该是需要具有这样的几个特性的:数据实时性、容错性而需要这些特性的App,一般就与直播、语音等流媒体挂钩。

TCP

001. 报文结构

序列号

序列号的存在可以保障数据的组装顺序。

确认号

此时小于确认号的数据已经全部接收,告知数据通信方下一个期望接收到的数据。

标示位

  1. ACK:确认序号标志,为1时表示确认号有效,为0表示报文中不含确认信息,忽略确认号字段。
  2. PSH:指示接收方在接收到该报文段以后,应尽快将这个报文段交给应用程序。
  3. RST:重置连接标志,用于重置由于主机崩溃或其他原因而出现错误的连接,或者用于拒绝非法的报文段和拒绝连接请求。
  4. SYN:同步序号,用于建立连接过程。
  5. FIN:finish标志,用于释放连接。

窗口

即滑动窗口大小,用来告知发送端接受端的缓存大小,以此控制发送端发送数据的速率,从而达到流量控制。

检验和

防止数据包在传输过程中产生数据差错,若传输中发生此类问题,数据将被抛弃。

模拟TCP 数据传输代码:

# TCPCLient
from socket import *

clientName = "127.0.0.1"
clientPort = 1200
clientSocket = socket(AF_INET, SOCK_STREAM)
clientSocket.connect((clientName, clientPort))
clientSocket.send('11'.encode())
modified = clientSocket.recv(1024)
clientSocket.close()

# TCPServer
from socket import *

serverPort = 1200
serverSocket = socket(AF_INET, SOCK_STREAM)
serverSocket.bind(('', serverPort))
while True:
    message, clientAddress = serverSocket.recvfrom(2048)
    modifiedMessage = '1111'
    serverSocket.sendto(modifiedMessage.encode(), clientAddress)
复制代码

002. 可靠传输的四大保障

传输保障的机制的引入和底层不可靠的数据通信相关,不管是同轴电缆、光纤这些数据媒体都存在一定的传输错误,在下层无法进行数据保障的情况下,上层建筑的可靠传输建设就显得尤为重要了。

TCP中一共引入了四大保障机制:

  1. 检验和
  2. 确认机制: 接收方用于通知发送方数据是否已经被正确的进行了接收。
  3. 序号机制: 为发送方流向接收方的数据顺序编号,检查出丢失的数据分组。
  4. 定时器机制: 网络中存在可能因为阻塞而丢失或者延迟的数据包,但发送方的等待时间是有限的,为了能力的健全选择重新发送一个数据包。

003. 流量控制

发送方和接收方的数据交收能力是存在上限的,而阈值的控制,采用了窗口来决定可以收发的数据总量。

回退N步算法

GBN中将序号分割为4类:

  1. 已被确认
  2. 可用,还未发送
  3. 发送,还未确认
  4. 不可用

其中(可用,还未发送)+(发送,还未确认)两块组成我们所熟知的滑动窗口。

工作流程

GBN的工作流程上严格按照顺序收发的,对于服务端而言,它只知道下一个该ACK的数据是什么(接收方不做缓存),如果分组和当前服务器所记录的需要ACK的分组不保持一致,服务端就会选择丢弃,并返回当前需要的分组信息。

再上图中能够发现会连续重传3个ACK_1,也就产生了冗余确认,这样的情况下会出发快速重传机制,立刻重新发送分组2的数据包。

选择重传算法

选择重传算法其实可以算是对GBN算法的优化,在GBN中如果某个数据包被怀疑丢失时,后续所有已成功的接收的数据包全部会被抛弃,这也就导致了性能问题。而选择重传的做法是仅对那些怀疑被丢失的数据包重新发送而提升了整体性能。(同样是空间换时间的方案)

004. 拥塞控制

拥塞控制是为了解决过多的数据注入到网络,导致网络奔溃,超过负荷。当每个发送方发送数据大量的数据会注入到网络,如果不做出限制,网络就会因数据量过大超负荷变卡。而其解决方案可以分为以下两种:

端到端拥塞控制

在这类拥塞控制算法中还可以分出两类拥塞情况:1. 超时拥塞 2. 3次冗余拥塞。

  • 慢开始: 开始传输时的拥塞窗口大小仅为1
  • 拥塞避免: 正常情况下拥塞窗口的增加速度变为每次仅加 1。出现超时情况将拥塞窗口大小置为1,进入慢开始状态,收到3个重复的ACK将拥塞窗口置为原来的一半。
  • 快恢复: 拥塞窗口减半,阈值等于拥塞窗口大小,然后以每一轮RTT加1的速度进行恢复。

网络辅助的拥塞控制

这类拥塞控制算法的实习是通过在网络层的IP数据报首部封装一个ECN字段中,当网络中发生阻塞现象时,ECN会被经过的IP数据报携带送往目的主机,再由目的主机通知发送主机。发送主机响应拥塞信息,控制拥塞窗口大小,已实现对拥塞控制。

005. 三次握手

他的终极目标是为了确认双方是有完备的接收响应能力和发送能力的。

握手的实现顺序:

  1. 第一次握手:客户机向服务器发出包SYN。服务器确认了客户机有发送能力。
  2. 第二次握手:服务器确认客户机的包SYN,发送给客户机包SYN+ACK。客户机确认了服务器有接收相应和发送能力。
  3. 第三次握手:客户机确认服务器的包SYN+ACK,发送包ACK+Data给服务器。服务器确认了客户机有接收响应能力。(从第三次握手开始已经可以带上数据进行传输了)

为什么不采用二次握手

原因: 为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生资源浪费。

简单的说: 1号请求发出后,因网络原因延迟导致客户端重新发起了2号建立连接请求报文,当2号请求报文与服务器建立连接,一段时间后1号请求连接到达,再次建立新的TCP连接。而这个新的连接客户端对客户端而言是过时的,之后的数据传递也不会走这个连接,导致这个连接挂起,也就出现了资源浪费。

从另外一个角度看,这是一个两军对垒的问题。

吴军想打魏国,蜀军这天也想打魏国,但是他们单独的兵力攻克不下魏国,二者合力即可马到功成。于是吴军选择先派出使者去发出同盟请求,并协定以狼烟作为信号 (第一次握手开始),但是途径魏国,那可能使者就有掉脑袋或者被偷换的可能了 (数据包丢失或者数据位出错),到了蜀军以后,蜀军认可了这次的行动,然后送走了来使 (第一次握手成功,第二次握手开始),当然中间又要路过魏国,有可能出现上述情况。吴军收到了蜀军的回信,十分高兴,吴军立刻点了狼烟,就要告诉蜀军要冲去灭魏国了。(完成第二次握手,发出数据,开始第三次握手)

四次握手也不用说了,能用三次完成,为什么还要第四次浪费资源呢?

006. 四次挥手

挥手的实现顺序:

  1. 第一次挥手:客户机向服务器发送包FIN本身进入半关闭状态,此时客户端只收不发。
  2. 第二次挥手:服务器确认客户机的包FIN,发送给客户机包ACK服务器确认了客户机需要关闭资源的要求。
  3. 第三次挥手:服务器向客户机发送包FIN同时本身进入Last_Ack状态。
  4. 第四次挥手:客户机确认服务器的包FIN+ACK,发送给服务器ACK,完成挥手。客户机确认了服务器需要关闭资源。

为什么不是两次挥手或者三次挥手呢?

如果是两次挥手,客户端发送一次关闭请求后,服务端会返回一个关闭成功的响应,然后本身断开连接(二次挥手本身已经不再有重传能力)。而网络是一个不可靠的传输,这个关闭成功的Response可能在网络中丢失,这就可能导致客户端的数据连接长期维护,也就造成了资源浪费。

如果是三次挥手,其实就是将四次挥手中的中间的两次握手内容融合进行数据传输。但服务端的FIN 数据需要等到客户端的所有请求已经完成才会发送,中间会产生较大的延时,而客户端长期没有收到服务端的响应,也会不断重发FIN 的数据导致无端的消耗。

007. SYN洪泛攻击的攻防策略

半连接队列以及全连接队列

当服务端进入SYN_RCVD 状态时,就进入了半连接队列。当服务端进入ESTABLISHED 状态时,就进入了全连接队列。

SYN洪泛攻击原理及后果

原理: 由客户端短时间内伪造不存在的IP 地址,向同一个服务端发起TCP 连接请求。

后果: 回到之前的半连接队列概念中,因为IP 是伪造的,对于服务器而言这些大量的TCP 连接会全部滞留在半连接队列中,而这个半连接队列显然是有界的,如果半连接队列挤满了,后续本有效的TCP 的连接将全部被抛弃。

应对方案

  1. 增加半连接队列的长度
  2. 减少服务器的重试次数
  3. 抛弃半连接队列,SYN Cookie技术。服务器在接收到客户端的请求后,根据请求的SYN 编撰对应Cookie,并在第二次握手时携带上这份数据,第三次握手时客户端需携带这份数据,服务端进行校验,如果满足要求才进行资源分配,也就是进入全连接队列。

参考资料

  1. 《计算机网络-自顶向下方法》
  2. 计算机网络:这是一份全面& 详细 HTTP知识讲解