【面试 - 八股文】网络协议万字总结,助你吊打面试官系列
大家好,我是温大大
最近温大大又又又整理了:万字网络协议方面的总结
主要覆盖:网络基础、TCP/UDP 高频面试题、HTTP 协议、Cookis/session、滑动窗口机制等知识点。
这次「网络八股文」配合前两次
这样同学们的基础八股文算是覆盖全了:数据库、Linux、网络 就像凑齐七龙珠能召唤 1 个神龙许愿 1 个愿望一样,如果你好好的阅读下温大大这三篇文章, 保证你能实现「涨薪」愿望呀。
温大大的肝算是快到爆穿了,只求各位同学帮忙一键三连:点赞、在看、转发
目录
网络分层基础
0.1 OSI 七层模型 与 TCP 五层模型
0.2 五层模型 vs 网络协议有哪些?
0.3 什么是面向有连接 vs 面向无连接?
0.4 UDP 和 TCP 的区别是什么?
0.5 TCP 对应的应用层协议有哪些?
0.6 UDP 对应的应用层协议有哪些?
TCP 高频面试题
1.1 TCP 三次握手(快速理解)
1.2 TCP 三次握手(深度理解)
1.3 TCP 两次握手可以吗?
1.4 TCP 四次挥手(快速理解)
1.5 TCP 四次挥手(深度理解)
1.6 TCP 第四次挥手为什么要等待 2MSL?
HTTP 协议
2.1 HTTP 协议的特点?
2.2 HTTP 报文格式
2.3 HTTP 状态码有哪些?
2.4 HTTPPOST 和 GET 的区别?
2.5 HTTP 长连接和短连接?
2.6 HTTP1.1 和 HTTP2.0 的区别?
2.7 HTTPS 与 HTTP 的区别?
2.8 HTTPS 原理(开始理解)
2.9 HTTPS 原理(深入理解)
传输 & 解析
3.1 什么是数字证书?
3.2 DNS 的解析过程?
3.3 浏览器中输入 URL 返回页面过程?
3.4 什么是对称加密和非对称加密?
缓存技术
4.1 什么是 cookie 和 session?
4.2 Cookie 和 Session 的区别?
网络异常处理
5.1 滑动窗口机制
5.2 详细讲一下拥塞控制?
5.3 拥塞避免
5.4 快重传
5.5 快恢复
0. 网络分层基础
0.1 OSI 七层模型 与 TCP 五层模型
OSI 七层模型:
应用层:为应用程序提供网络服务;
表示层:数据格式转换、数据压缩和数据加密;
会话层:建立、断开和维护通信链接;
传输层:为上层协议提供端到端的可靠传输;
网络层:寻址和路由;
数据链路层:定义通过通信媒介互连的设备之间传输的规范;
物理层:利用物理传输介质为数据链路层提供物理连接。
TCP 五层模型:
相比 OSI 七层模型,将 OSI 的应用层、表示层和会话层合为一层:应用层,其他不变。
0.2 五层模型 vs 网络协议有哪些?
0.3 什么是面向有连接 vs 面向无连接
面向有连接
传输:会话建立、传输数据和会话断开
传输可靠性包括:超时重传、流量控制等
常见协议:TCP
面向无连接型
传输:仅提供基本的传输数据的功能,即使接收端不存在,
发送端也能发送数据包,
常见协议:UDP、IP。
0.4 UDP 和 TCP 的区别是什么?
相同:
UDP 和 TCP 都是传输层的协议
区别:
TCP 是面向有连接型,UDP 是面向无连接型;
TCP 是一对一传输,UDP 支持一对一、一对多、多对一和多对多的交互通信;
TCP 是面向字节流的,即把应用层传来的报文看成字节流,将字节流拆分成大小不等的数据块,并添加 TCP 首部;UDP 是面向报文的,对应用层传下来的报文不拆分也不合并,仅添加 UDP 首部;
TCP 支持传输可靠性的多种措施,包括保证包的传输顺序、重发机制、流量控制和拥塞控制;
UDP 仅提供最基本的数据传输能力。
0.5 TCP 对应的应用层协议有哪些?
FTP:文件传输协议; SSH:远程登录协议; HTTP:web 服务器传输超文本到本地浏览器的超文本传输协议。 UDP 对应的典型的应用层协议:
0.6 UDP 对应的应用层协议有哪些?
DNS:域名解析协议; TFTP:简单文件传输协议; SNMP:简单网络管理协议。
1. TCP 高频面试题
1.1 TCP 三次握手(快速理解)
A 向 B 发起建立连接请求:A——>B;
B 收到 A 的发送信号,并且向 A 发送确认信息:B——>A;
A 收到 B 的确认信号,并向 B 发送确认信号:A——>B。
三次握手大概就是这么个过程。
通过第一次握手,B 知道 A 能够发送数据。
通过第二次握手,A 知道 B 能发送数据。
结合第一次握手和第二次握手,A 知道 B 能接收数据。
结合第三次握手,B 知道 A 能够接收数据。
至此,完成了握手过程,A 知道 B 能收能发,B 知道 A 能收能发,通信连接至此建立。 三次连接是保证可靠的最小握手次数,再多次握手也不能提高通信成功的概率,反而浪费资源。
1.2 TCP 三次握手(深度理解)
备注:
A 代表 客户端
B 代表 服务端
第一次握手:
A 向 B 发起建立连接请求,A 会随机生成一个起始序列号 x
A 向 B 发送的字段中包含标志位 SYN=1,序列号 seq=x
第一次握手前 A 的状态为 CLOSE
第一次握手后 A 的状态为 SYN-SENT
此时 B 的状态为 LISTEN
总结:A 发 (SYN=1,seq=x)到 B
第二次握手:
B 在收到 A 发来的报文后,会随机生成一个 B 的起始序列号 y,
然后给客户端回复一段报文,其中包括标志位 SYN=1,ACK=1,序列号 seq=y,确认号 ack=x+1。
第二次握手前服务端的状态为 LISTEN,第二次握手后服务端的状态为 SYN-RCVD,此时客户端的状态为 SYN-SENT。(其中 SYN=1 表示要和客户端建立一个连接,ACK=1 表示确认序号有效)
总结:B 发(SYN=1, ACK=1, seq=y, ack=x+1)到 A
第三次握手:
A 收到 B 发来的报文后,会再向 B 发送报文,
其中包含标志位 ACK=1,序列号 seq=x+1,确认号 ack=y+1。
第三次握手前客户端的状态为 SYN-SENT,第三次握手后客户端和服务端的状态都为 ESTABLISHED。
此时连接建立完成。 总结:A 发(ACK=1, seq=x+1, ack=y+1)到 B
1.3 TCP 两次握手可以吗?
不可以。
防止已失效的连接请求报文段突然又传输到了服务端,导致产生问题。
比如客户端 A 发出连接请求,可能因为网络阻塞原因,A 没有收到确认报文,于是 A 再重传一次连接请求。
连接成功,等待数据传输完毕后,就释放了连接。
然后 A 发出的第一个连接请求等到连接释放以后的某个时间才到达服务端 B,此时 B 误认为 A 又发出一次新的连接请求,于是就向 A 发出确认报文段。
1.4 TCP 四次挥手(快速理解)
那为什么需要四次挥手呢?请看如下过程:
A 向 B 发起请求,表示 A 没有数据要发送了:A——>B;
B 向 A 发送信号,确认 A 的断开请求:B——>A;
B 向 A 发送信号,请求断开连接,表示 B 没有数据要发送了:B——>A;
A 向 B 发送确认信号,同意断开:A——>B。
B 收到确认信号,断开连接,而 A 在一段时间内没收到 B 的信号,表明 B 已经断开了,于是 A 也断开了连接。至此,完成挥手过程。
可能有捧油会问,为什么 2、3 次挥手不能合在一次挥手中?那是因为此时 A 虽然不再发送数据了,但是还可以接收数据,B 可能还有数据要发送给 A,所以两次挥手不能合并为一次。
挥手次数比握手多一次,是因为握手过程,通信只需要处理连接。而挥手过程,通信需要处理数据+连接。
1.5 TCP 四次挥手(深度理解)
A 的应用进程先向其 TCP 发出连接释放报文段(FIN=1,seq=u),并停止再发送数据,主动关闭 TCP 连接,进入 FIN-WAIT-1(终止等待 1)状态,等待 B 的确认。
B 收到连接释放报文段后即发出确认报文段(ACK=1,ack=u+1,seq=v),B 进入 CLOSE-WAIT(关闭等待)状态,此时的 TCP 处于半关闭状态,A 到 B 的连接释放。
A 收到 B 的确认后,进入 FIN-WAIT-2(终止等待 2)状态,等待 B 发出的连接释放报文段。
B 发送完数据,就会发出连接释放报文段(FIN=1,ACK=1,seq=w,ack=u+1),B 进入 LAST-ACK(最后确认)状态,等待 A 的确认。
A 收到 B 的连接释放报文段后,对此发出确认报文段(ACK=1,seq=u+1,ack=w+1),A 进入 TIME-WAIT(时间等待)状态。此时 TCP 未释放掉,需要经过时间等待计时器设置的时间 2MSL(最大报文段生存时间)后,A 才进入 CLOSED 状态。B 收到 A 发出的确认报文段后关闭连接,若没收到 A 发出的确认报文段,B 就会重传连接释放报文段。
1.6 TCP 第四次挥手为什么要等待 2MSL?
保证 A 发送的最后一个 ACK 报文段能够到达 B。
这个 ACK 报文段有可能丢失,B 收不到这个确认报文,就会超时重传连接释放报文段,然后 A 可以在 2MSL 时间内收到这个重传的连接释放报文段,接着 A 重传一次确认,重新启动 2MSL 计时器,最后 A 和 B 都进入到 CLOSED 状态,若 A 在 TIME-WAIT 状态不等待一段时间,而是发送完 ACK 报文段后立即释放连接,则无法收到 B 重传的连接释放报文段,所以不会再发送一次确认报文段,B 就无法正常进入到 CLOSED 状态。
防止已失效的连接请求报文段出现在本连接中。
A 在发送完最后一个 ACK 报文段后,再经过 2MSL,就可以使这个连接所产生的所有报文段都从网络中消失,使下一个新的连接中不会出现旧的连接请求报文段。
2. HTTP 协议
2.1 HTTP 协议的特点?
HTTP 允许传输任意类型的数据。传输的类型由 Content-Type 加以标记。
无状态。对于客户端每次发送的请求,服务器都认为是一个新的请求,上一次会话和下一次会话之间没有联系。
支持客户端/服务器模式。
2.2 HTTP 报文格式
HTTP 请求由请求行、请求头部、空行和请求体四个部分组成。
请求行:包括请求方法,访问的资源 URL,使用的 HTTP 版本。GET 和 POST 是最常见的 HTTP 方法,除此以外还包括 DELETE、HEAD、OPTIONS、PUT、TRACE。
请求头:格式为“属性名:属性值”,服务端根据请求头获取客户端的信息,主要有 cookie、host、connection、accept-language、accept-encoding、user-agent。
请求体:用户的请求数据如用户名,密码等。
2.3 HTTP 状态码有哪些?
2.4 HTTP POST 和 GET 的区别?
GET 请求参数通过 URL 传递,POST 的参数放在请求体中。
GET 产生一个 TCP 数据包;POST 产生两个 TCP 数据包。对于 GET 方式的请求,浏览器会把请求头和请求体一并发送出去;而对于 POST,浏览器先发送请求头,服务器响应 100 continue,浏览器再发送请求体。
GET 请求会被浏览器主动缓存,而 POST 不会,除非手动设置。
GET 请求只能进行 url 编码,而 POST 支持多种编码方式。
GET 请求参数会被完整保留在浏览器历史记录里,而 POST 中的参数不会被保留。
2.5 HTTP 长连接和短连接?
短连接
连接->传输数据->关闭连接
比如 HTTP 是无状态的的短链接,浏览器和服务器每进行一次 HTTP 操作,就建立一次连接,但任务结束就中断连接。
因为连接后接收了数据就断开了,所以每次数据接受处理不会有联系。 这也是 HTTP 协议无状态的原因之一。
长连接
连接->传输数据->保持连接 -> 传输数据-> ...........->直到一方关闭连接,多是客户端关闭连接。
长连接指建立 SOCKET 连接后不管是否使用都保持连接,但安全性较差。
长链接使用场景
长连接多用于操作频繁,点对点的通讯,而且连接数不能太多情况。每个 TCP 连接都需要三步握手,
这需要时间,如果每个操作都是先连接,再操作的话那么处理速度会降低很多,所以每个操作完后都
不断开,次处理时直接发送数据包就 OK 了,不用建立 TCP 连接。例如:数据库的连接用长连接, 如果用短连接频繁的通信会造成 socket 错误,而且频繁的 socket 创建也是对资源的浪费。
短链接使用场景
而像 WEB 网站的 http 服务一般都用短链接,因为长连接对于服务端来说会耗费一定的资源,
而像 WEB 网站这么频繁的成千上万甚至上亿客户端的连接用短连接会更省一些资源,如果用长连接,而且同时有成千上万的用户,如果每个用户都占用一个连接的话,那可想而知吧。所以并发量大,但每个用户无需频
繁操作情况下需用短连好。
2.6 HTTP 1.1 和 HTTP2.0 的区别?
区别 1: 解析协议不同
http1 协议解析 基于文本解析
http2.0 协议解析 基于二进制
区别 2: HTTP2.0 采用多路复用(Mutiplexing)
一个连接上可以有多个 request,且可以随机的混在一起,每个不同的 request 都有对应的 id,服务端可以通过 request_id 来辨别,大大加快了传输速率
区别 3: http2.0 header 压缩:
http1.x 中的 header 需要携带大量信息.而且每次都要重复发送.
http2.0 使用 encode 来减少传输的 header 大小.而且客户端和服务端可以各自缓存(cache)一份 header filed 表,避免了 header 的重复传输,还可以减少传输的大小. 服务端推送(server push): 可以通过解析 html 中的依赖,只能的返回所需的其他文件(css 或者 js 等),而不用再发起一次请求.
区别 4: http2.0 服务端推送(server push):
可以通过解析 html 中的依赖,只能的返回所需的其他文件(css 或者 js 等),而不用再发起一次请求.
2.7 HTTPS 与 HTTP 的区别?
HTTP 明文传输,安全性较差,HTTPS 加密传输,安全性较好。
HTTPS 协议需要到 CA(Certificate Authority,数字证书认证机构) 申请证书,一般免费证书较少,因而需要一定费用。
HTTP 页面响应速度比 HTTPS 快,主要是因为 HTTP 使用 TCP 三次握手建立连接,客户端和服务器需要交换 3 个包,而 HTTPS 除了 TCP 的三个包,还要加上 ssl 握手需要的 9 个包,所以一共是 12 个包。
HTTP 和 HTTP 使用的是完全不同的连接方式,用的端口也不一样,前者是 80,后者是 443。
HTTPS 其实就是建构在 SSL/TLS 之上的 HTTP 协议,所以,要比较 HTTPS 比 HTTP 要更耗费服务器资源。
2.8 HTTPS 原理(快速理解)
HTTPS 默认工作在 TCP 协议 443 端口,它的工作流程一般如以下方式:
1、TCP 三次同步握手
2、客户端验证服务器数字证书
3、DH 算法协商对称加密算法的密钥、hash 算法的密钥
4、SSL 安全加密隧道协商完成
5、网页以加密的方式传输,用协商的对称加密算法和密钥加密,保证数据机密性;用协商的 hash 算法进行数据完整性保护,保证数据不被篡改。
2.9 HTTPS 原理(深入理解)
1、客户端发起 HTTPS 请求
这个没什么好说的,就是用户在浏览器里输入一个 https 网址,然后连接到 server 的 443 端口。
2、服务端的配置
采用 HTTPS 协议的服务器必须要有一套数字证书,可以自己制作,也可以向组织申请,区别就是自己颁发的证书需要客户端验证通过,才可以继续访问,而使用受信任的公司申请的证书则不会弹出提示页面(startssl 就是个不错的选择,有 1 年的免费服务)。
这套证书其实就是一对公钥和私钥,如果对公钥和私钥不太理解,可以想象成一把钥匙和一个锁头,只是全世界只有你一个人有这把钥匙,你可以把锁头给别人,别人可以用这个锁把重要的东西锁起来,然后发给你,因为只有你一个人有这把钥匙,所以只有你才能看到被这把锁锁起来的东西。
3、传送证书
这个证书其实就是公钥,只是包含了很多信息,如证书的颁发机构,过期时间等等。
4、客户端解析证书
这部分工作是有客户端的 TLS 来完成的,首先会验证公钥是否有效,比如颁发机构,过期时间等等,如果发现异常,则会弹出一个警告框,提示证书存在问题。
如果证书没有问题,那么就生成一个随机值,然后用证书对该随机值进行加密,就好像上面说的,把随机值用锁头锁起来,这样除非有钥匙,不然看不到被锁住的内容。
5、传送加密信息
这部分传送的是用证书加密后的随机值,目的就是让服务端得到这个随机值,以后客户端和服务端的通信就可以通过这个随机值来进行加密解密了。
6、服务端解密信息
服务端用私钥解密后,得到了客户端传过来的随机值(私钥),然后把内容通过该值进行对称加密,所谓对称加密就是,将信息和私钥通过某种算法混合在一起,这样除非知道私钥,不然无法获取内容,而正好客户端和服务端都知道这个私钥,所以只要加密算法够彪悍,私钥够复杂,数据就够安全。
7、传输加密后的信息
这部分信息是服务段用私钥加密后的信息,可以在客户端被还原。
8、客户端解密信息
客户端用之前生成的私钥解密服务段传过来的信息,于是获取了解密后的内容,整个过程第三方即使监听到了数据,也束手无策。
3. 传输 & 解析
3.1 什么是数字证书?
简介
服务端可以向证书颁发机构 CA 申请证书,以避免中间人攻击(防止证书被篡改)。
证书包含三部分内容:证书内容、证书签名算法和签名,签名是为了验证身份。
服务端把证书传输给浏览器,浏览器从证书里取公钥。证书可以证明该公钥对应本网站。
制作过程
CA 使用证书签名算法对证书内容进行 hash 运算。
对 hash 后的值用 CA 的私钥加密,得到数字签名。
浏览器验证过程
获取证书,得到证书内容、证书签名算法和数字签名。
用 CA 机构的公钥对数字签名解密(由于是浏览器信任的机构,所以浏览器会保存它的公钥)。
用证书里的签名算法对证书内容进行 hash 运算。
比较解密后的数字签名和对证书内容做 hash 运算后得到的哈希值,相等则表明证书可信。
3.2 DNS 的解析过程?
浏览器搜索自己的 DNS 缓存
若没有,则搜索操作系统中的 DNS 缓存和 hosts 文件
若没有,则操作系统将域名发送至本地域名服务器,本地域名服务器查询自己的 DNS 缓存,查找成功则返回结果,否则依次向根域名服务器、顶级域名服务器、权限域名服务器发起查询请求,最终返回 IP 地址给本地域名服务器
本地域名服务器将得到的 IP 地址返回给操作系统,同时自己也将 IP 地址缓存起来
操作系统将 IP 地址返回给浏览器,同时自己也将 IP 地址缓存起来
浏览器得到域名对应的 IP 地址
3.3 浏览器中输入 URL 返回页面过程?
解析域名,找到主机 IP。
浏览器利用 IP 直接与网站主机通信,三次握手,建立 TCP 连接。浏览器会以一个随机端口向服务端的 web 程序 80 端口发起 TCP 的连接。
建立 TCP 连接后,浏览器向主机发起一个 HTTP 请求。
服务器响应请求,返回响应数据。
浏览器解析响应内容,进行渲染,呈现给用户。
3.4 什么是对称加密和非对称加密?
对称加密:通信双方使用相同的密钥进行加密。特点是加密速度快,但是缺点是密钥泄露会导致密文数据被破解。常见的对称加密有 AES 和 DES 算法。
非对称加密:它需要生成两个密钥,公钥和私钥。公钥是公开的,任何人都可以获得,而私钥是私人保管的。公钥负责加密,私钥负责解密;或者私钥负责加密,公钥负责解密。这种加密算法安全性更高,但是计算量相比对称加密大很多,加密和解密都很慢。常见的非对称算法有 RSA 和 DSA。
4. 缓存技术
4.1 什么是 cookie 和 session?
什么是 Cookie(客户端技术)
Cookie 实际上是一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就使用 response 向客户端浏览器颁发一个 Cookie。客户端会把 Cookie 保存起来。
当浏览器再请求该网站时,浏览器把请求的网址连同该 Cookie 一同提交给服务器。服务器检查该 Cookie,以此来辨认用户状态。服务器还可以根据需要修改 Cookie 的内容。
信息保存的时间可以根据需要设置.
如果没有设置 Cookie 失效日期,它们仅保存到关闭浏览器程序为止.
如果将 Cookie 对象的 Expires 属性设置为 Minvalue,则表示 Cookie 永远不会过期.
Cookie 存储的数据量很受限制,大多数浏览器支持最大容量为 4K,因此不要用来保存数据集及其他大量数据.
由于并非所有的浏览器都支持 Cookie,并且数据信息是以明文文本的形式保存在客户端的计算机中,
因此最好不要保存敏感的,未加密的数据,否则会影响网站的安全性
什么是 Session(服务端技术)
Session 是另一种记录客户状态的机制,不同的是 Cookie 保存在客户端浏览器中,而 Session 保存在服务器上。客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上。这就是 Session。客户端浏览器再次访问时只需要从该 Session 中查找该客户的状态就可以了。
每个用户访问服务器都会建立一个 session,那服务器是怎么标识用户的唯一身份呢?事实上,用户与服务器建立连接的同时,服务器会自动为其分配一个 SessionId。
4.2 Cookie 和 Session 的区别?
1、数据存储位置:cookie 数据存放在客户的浏览器上,session 数据放在服务器上。
2、安全性:cookie 不是很安全,别人可以分析存放在本地的 cookie 并进行 cookie 欺骗,考虑到安全应当使用 session。
3、服务器性能:session 会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用 cookie。
4、数据大小:单个 cookie 保存的数据不能超过 4K,很多浏览器都限制一个站点最多保存 20 个 cookie。
5、信息重要程度:可以考虑将登陆信息等重要信息存放为 session,其他信息如果需要保留,可以放在 cookie 中。
5. 网络异常处理
5.1 滑动窗口机制
在 TCP 协议当中窗口机制分为两种:
1.固定的窗口大小
2.滑动窗口
固定窗口存在的问题
我们假设这个固定窗口的大小为 1,也就是每次只能发送一个数据,只有接收方对这个数据进行了确认后才能发送第二个数据。在图中我们可以看到,发送方每发送一个数据接收方就要给发送方一个 ACK 对这个数据进行确认。只有接收了这个确认数据以后发送方才能传输下个数据。
存在的问题:如果窗口过小,当传输比较大的数据的时候需要不停的对数据进行确认,这个时候就会造成很大的延迟。
如果窗口过大,我们假设发送方一次发送 100 个数据,但接收方只能处理 50 个数据,这样每次都只对这 50 个数据进行确认。发送方下一次还是发送 100 个数据,但接受方还是只能处理 50 个数据。这样就避免了不必要的数据来拥塞我们的链路。
因此,我们引入了滑动窗口
1.滑动窗口概述
滑动窗口通俗来讲就是一种流量控制技术。
它本质上是描述接收方的 TCP 数据报缓冲区大小的数据,发送方根据这个数据来计算自己最多能发送多长的数据,如果发送方收到接收方的窗口大小为 0 的 TCP 数据报,那么发送方将停止发送数据,等到接收方发送窗口大小不为 0 的数据报的到来
2.工作原理
第一次发送数据这个时候的窗口大小是根据链路带宽的大小来决定的。
假设这时候的窗口是 3.这个时候接收方收到数据以后会对数据进行确认告诉哦发送方我下次希望收到的数据是多少。
在上图中:我们看到接收方发送的 ACK = 3(这是对发送方发送序列 2 的回答确认,下一次接收方期望接收到的是 3 序列信号),这个时候发送方收到这个数据以后就知道我第一次发送的 3 个数据对方只收到了两个,就知道第三个数据对方没有收到,下次返送的时候就从第 3 个数据开始发。这时候窗口大小就变为了 2.
看到接收方发送的 ACK 是 5 就表示他下一次希望收到的数据是 5,发送方就知道我刚才发送的 2 个数据对方收到了,这个时候开始发送第 5 个数据。
当链路变好或者变差,这个窗口还会发生变化,并不是第一次协商好了以后就永远不会变化了。
3.死锁状态
(1)概述:
当接收端向发送端发送零窗口报文段后不久,接收端的接收缓存又有了一些存储空间,于是接收端向发送端发送了 Windows size = 2 的报文段,然而这个报文段在传输过程中丢失了。发送端一直等待收到接收端发送的非零窗口的通知,而接收端一直等待发送端发送数据,这样就死锁了。
(2)解决方法
TCP 为每个连接设有一个持续计时器。只要 TCP 连接的一方收到对方的零窗口通知,就启动持续计时器,若持续计时器设置的时间到期,就发送一个零窗口探测报文段(仅携带 1 字节的数据),而对方就在确认这个探测报文段时给出了现在的窗口值。
4.TCP 报文段的发送时机(传输效率问题)
可以用以下三种不同的机制控制 TCP 报文段的发送时机:
(1)TCP 维持一个变量 MSS,等于最大报文段的长度。只要缓冲区存放的数据达到 MSS 字节时,就组装成了一个 TCP 报文段发送出去
(2)由发送方的应用进程指明要发送的报文段,即:TCP 支持推送操作
(3)发送方的一个计时器期限到了,这时就把当前已有的缓存数据装入报文段(但长度不能超过 MSS)发送出去。
5.2 详细讲一下拥塞控制?
一、为何要进行拥塞控制?
为了方便,我们假设主机 A 给主机 B 传输数据。
我们知道,两台主机在传输数据包的时候,如果发送方迟迟没有收到接收方反馈的 ACK,那么发送方就会认为它发送的数据包丢失了,进而会重新传输这个丢失的数据包。
然而实际情况有可能此时有太多主机正在使用信道资源,导致网络拥塞了,而 A 发送的数据包被堵在了半路,迟迟没有到达 B。这个时候 A 误认为是发生了丢包情况,会重新传输这个数据包。
结果就是不仅浪费了信道资源,还会使网络更加拥塞。因此,我们需要进行拥塞控制。
二、如何知道网络的拥塞情况?
A 与 B 建立连接之后,就可以向 B 发送数据了,然而这个时候 A 并不知道此时的网络拥塞情况如何,也就是说,A 不知道一次性连续发送多少个数据包好,我们也把 A 一次性连续发送多少个数据包称之为拥塞窗口,用 N 代表此时拥塞窗口的大小吧。
为了探测网络的拥塞情况,我们可以采取以下两种策略:
1、先发送一个数据包试探下,如果该数据包没有发生超时事件(也就是没有丢包)。那么下次发送时就发送 2 个,如果还是没有发生超时事件,下次就发送 3 个,以此类推,即 N = 1, 2, 3, 4, 5.....
2、一个一个增加实在是太慢了,所以可以刚开始发送 1 个,如果没有发生超时时间,就发送 2 个,如果还是没有发送超时事件就发送 4 个,接着 8 个...,用翻倍的速度类推,即 N = 1, 2, 4, 8, 16...
无论是第一种方法还是第二种方法,最后都会出现瓶颈值。不过这里值得注意的是,第一种情况的增长速率确实有点慢,但是第二种情况以指数增长,增长速度有点太快了,可能一下子就到瓶颈值了。
为了解决这个过慢或过快的问题,我们可以把第一种方法和第二种方法结合起来。也就是说,我们刚开始可以以指数的速度增长,增长到某一个值,我们把这个值称之为阈值吧,用变量 ssthresh 代替。当增长到阈值时,我们就不在以指数增长了,而是一个一个线性增长。
所以最终的策略是:前期指数增长,到达阈值之后,就以一个一个线性的速度来增长。
(注:8 之后其实是直线的,那里只是弯曲了一下)
我们也把指数增长阶段称之为慢启动,线性增长阶段称之为拥塞避免
三、到了瓶颈值之后怎么办? 无论是指数增长还是一个一个增长,最终肯定会出现超时事件,总不可能无限增长吧。当出现超时事件时,我们就认为此时网络出现了拥塞了,不能再继续增长了。我们就把这个时候的 N 的值称之为瓶颈值吧,用 MAX 这个字母来代替吧,即最大值。
注:这里再次提醒阈值过后是一个一个线性增长,图中之所以弯曲是因为我画图原因导致的
当达到最大值 MAX 之后,我们该怎么办呢?
当到达最大值之后我们采取的策略是这样的:
我们就回到最初的最初的状态,也就是说从 1,2,4,8.....开始,不过这个时候我们还会把 ssthresh 调小,调为 MAX 值的一半,即 ssthresh = MAX / 2。
图中阈值为 8,瓶颈值是 14;超时事件发生后,阈值为 14 / 2 = 7。
四、超时事件就一定是网络拥塞? 超时事件发送就一定是网络出现了拥堵吗?其实也有可能不是出现了网络拥堵,有可能是因为某个数据包出现了丢失或者损害了,导致了这个数据包超时事件发生了
为了防止这种情况,我们是通过冗余 ACK 来处理的。我们都知道,数据包是有序号的,如果 A 给 B 发送 M1, M2, M3, M4, M5...N 个数据包,如果 B 收到了 M1, M2, M4....却始终没有收到 M3,这个时候就会重复确认 M2,意在告诉 A,M3 还没收到,可能是丢失
当 A 连续收到了三个确认 M2 的 ACK,且 M3 超时事件还没发生。A 就知道 M3 可能丢失了,这个时候 A 就不必等待 M3 设置的计时器到期了,而是快速重传 M3。并且把 ssthresh 设置为 MAX 的一半,即 ssthresh = MAX/2,但是这个时候并非把控制窗口 N 设置为 1,而是让 N = ssthresh,N 在一个一个增长。
我们也把这种情况称之为快速恢复。而这种具有快速恢复的 TCP 版本称之为 TCP Reno。
还有另外一种 TCP 版本,无论是收到三个相同的 ACK 还是发生超时事件,都把拥塞窗口的大小设为 1,从最初状态开始,这种版本的 TCP 我们称之为 TCP Tahoe。
5.3 拥塞避免
让拥塞窗口 cwnd 缓慢地增大,每经过一个往返时间 RTT 就把发送方的拥塞窗口 cwnd 加 1,而不是加倍。这样拥塞窗口 cwnd 按线性规律缓慢增长。
无论在慢开始阶段还是在拥塞避免阶段,只要发送方判断网络出现拥塞(其根据就是没有收到确认),就要把慢开始门限 ssthresh 设置为出现拥塞时的发送 方窗口值的一半(但不能小于 2)。然后把拥塞窗口 cwnd 重新设置为 1,执行慢开始算法。这样做的目的就是要迅速减少主机发送到网络中的分组数,使得发生 拥塞的路由器有足够时间把队列中积压的分组处理完毕。
5.4 快重传
有时个别报文段会在网络中丢失,但实际上网络并未发生拥塞。如果发送方迟迟收不到确认,就会产生超时,就会误认为网络发生了拥塞。这就导致发送方错误地启动慢开始,把拥塞窗口 cwnd 又设置为 1,因而降低了传输效率。
快重传算法可以避免这个问题。快重传算法首先要求接收方每收到一个失序的报文段后就立即发出重复确认,使发送方及早知道有报文段没有到达对方。
发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段,而不必继续等待重传计时器到期。由于发送方尽早重传未被确认的报文段,因此采用快重传后可以使整个网络吞吐量提高约 20%。
5.5 快恢复
当发送方连续收到三个重复确认,就会把慢开始门限 ssthresh 减半,接着把 cwnd 值设置为慢开始门限 ssthresh 减半后的数值,然后开始执行拥塞避免算法,使拥塞窗口缓慢地线性增大。
在采用快恢复算法时,慢开始算法只是在 TCP 连接建立时和网络出现超时时才使用。 采用这样的拥塞控制方法使得 TCP 的性能有明显的改进。
关注我,加我好友拉你进面试群,一起讨论面试干货 / 套路, 大家一起升职加薪
版权声明: 本文为 InfoQ 作者【测试猿温大大】的原创文章。
原文链接:【http://xie.infoq.cn/article/f16610b4e5609ba473ef1ca4b】。文章转载请联系作者。
评论