计算机网络学习笔记(原告:小林coding)

文章目录

TCP/IP网络模型

  1. 应用层: 俩不同设备的应用要通信时,应用就把数据传给传输层。(用户态)
  2. 传输层:TDP/UDP协议,数据包超过MSS(TCP最大报文段长度),就将数据包分块,每个分块称为一个TCP段(TCP Segment)
  3. 网络层: IP协议,IP报文超过MTU 会再次分片 IP地址做区分设备。网络号:负责标识该IP地址属于哪个 子网; 主机号:负责标识同一 子网 下的不同主机;
    IP 协议的寻址: 告诉我们去往下一个目的地该朝哪个方向走;
    路由: 根据「下一个目的地」选择路径。寻址像在导航,路由像在操作方向盘;
  4. 网络接口层: 给生成的IP头部前加上MAC(采用相匹配的方式 以太网通讯)头部,封装成数据帧发送到网络上。MAC头部是以太网使用的头部,包含了接收和发送方的MAC地址等信息,可通过ARP协议获取对方MAC地址。

键入网址到网页显示,期间发生了什么?

孤单小弟——HTTP

  1. 解析URL
    浏览器对URL解析生成发送给web服务器的请求信息
  2. 生成HTTP请求信息
    在这里插入图片描述

真实地址查询——DNS

委托操作系统将生成的HTTP消息发送给web服务器
发送前: 查询服务器域名对应的IP地址 (DNS服务器里面查)

  1. 域名层级关系,域名中越靠右位置表示层级越高 例如www.server.com. , 最后一个点 . 根域名在最顶层,下一层是 .com顶级域,再下面是server.com
    域名层级关系类似树结构:
      根DNS服务器( . )
      顶级域DNS服务器( .com )
      权威DNS服务器( server.com )
  2. 域名解析工作流程
      客户端先发一个DNS请求问www.server.com的IP是啥,并发给本地DNS服务器
      若能在本地域名服务器缓存的表格里找到www.server.com,直接返回IP地址,否则问他的根域名服务器。
      根域名服务器收到本地DNS请求后,给出.com顶级域名服务器地址
      根据上面地址询问顶级域名,顶级域名给出权威DNS服务器地址
      权威DNS进行查询并给出IP地址,然后本地DNS将IP返回客户端

小林的下面这幅图很形象,用心了:
在这里插入图片描述
注:并不是每次都需要经过上述步骤,还有 缓存

指南好帮手——协议栈

DNS得到IP后,传输工作给操作系统中的协议栈

在这里插入图片描述
IP中ICMP协议:用于告知网络包传送过程中产生的错误以及各种控制信息;
IP中ARP协议: 用于根据IP地址查询相应的以太网MAC地址;

可靠传输——TCP

  1. TCP包头格式:源端口号和目标端口号、序号解决乱序问题、确认号解决丢包问题、状态位(SYN ACK RST FIN)、窗口大小(流量控制、拥塞控制)
  2. TCP三次握手: 目的是是双方都有发送和接收的能力
    在这里插入图片描述
    TCP连接状态:Linux中 netstat -napt
    HTTP请求消息超过了MSS长度,要进行TCP分割
    MTU:一个网络包的最大长度,以太网一般1500字节
    MSS:出去IP和TCP头部后,一个网络包所容纳的TCP数据的最大长度
  3. TCP报文生成
    TCP协议里有两个端口,浏览器监听的端口(随机生成的),web服务器监听的端口(HTTP默认80, HTTPS默认443)

远程定位——IP

IP协议——源地址IP:客户端输出的IP地址;
IP协议——目标地址: 通过DNS域名解析得到的Web服务器IP;
若客户端有多个网卡,就有多个IP,应该怎么选择?
  通过route -n查看路由表,服务器目标地址和各条目子网掩码与运算,匹配成功就是源地址,若都没有匹配就选默认网关 0.0.0.0;

两点传输——MAC

  生成IP头部后,在其前面加MAC头部,MAC包头里需要发送方MAC地址和接收方MAC地址,用于两点间传输。
  一般TCP/IP通信里,MAC协议类型有 0800:IP协议 0806:ARP协议
发送方:MAC地址是网卡生产时写入到ROM中的,直接读取;
接收方:MAC地址需要查路由表,匹配条目后获得对方IP地址,然后由ARP协议以广播的形式找到MAC地址;(也不用每次都广播,有个ARP缓存)

出口——网卡

数字信息转换为电信号(网卡,网卡驱动程序)
起始帧分界符:一个表示包起始位置的标记;
末尾FCS(帧校验序列): 用来检查包传输过程是否有损坏;

送别者——交换机

将网络包原样转发到目的地,工作在MAC层,也称二层网络设备。交换机根据MAC地址表查找MAC地址,然后将信号发送到相应的端口。若MAC地址表找不到指定的MAC地址,只能将包转发到除了源端口之外的所有端口上,无论该设备连接在哪个端口上都能收到这个包,因为只有相应的接收者才接收包,而其他设备会忽略这个包

出境大门——路由器

网络包经过交换机之后到达路由器,并被转发到下一个路由器或目标设备。
路由器与交换机区别:

  1. 路由器是基于 IP 设计的,俗称三层网络设备,路由器的各个端口都具有 MAC 地址和 IP 地址;
  2. 交换机是基于以太网设计的,俗称二层网络设备,交换机的端口不具有 MAC 地址。

互相扒皮——服务器与客户端

在这里插入图片描述

Linux系统如何收发网络包?

网络模型

OSI模型

  1. 应用层
  2. 表示层
  3. 会话层
  4. 传输层
  5. 网络层
  6. 数据链路层
  7. 物理层
    TCP/IP协议: 应用层 传输层 网络层 网络接口层

Linux接收网络包的流程(左图)

网卡接收到一个网络包后,会通过 DMA 技术,将网络包写入到指定的内存地址,也就是写入到Ring Buffer,这个是一个环形缓冲区,接着就会告诉操作系统这个网络包已经到达。(NAPI机制,混合中断和轮询)
软中断处理:内核中ksoftirqd线程专门负责

Linux发送网络包的过程(右图)

在这里插入图片描述

HTTP

1xx : 提示信息,还有后续操作;
2xx : 成功
3xx : 重定向
4xx : 客户端错误
5xx : 服务器错误

HTTP常见字段

Host 字段:客户端发送请求时,用来指定服务器域名。可将请求发往 同一台 服务器上的不同网站
Content-Length 字段: 服务器返回数据时,表明本次回应的数据长度。HTTP协议通过设置回车符、换行符作为HTTP header的边界,通过Content-Length字段作为HTTP body的边界,这两个方式都是解决“粘包”问题;
Connection 字段: 用与客户端要求服务器使用 [HTTP长连接] 机制,以便其他请求复用。( 开启Connection : keep-Alive )
HTTP长连接特点:只有任意一端没有明确提出断开连接,保持TCP连接状态;
Content-Type 字段: 告诉客户端回应数据的格式;
Content-Encoding 字段: 数据压缩方法,客户端通过Accept-Encoding说明自个可接受哪些压缩方法。

GET和POST

GET :从服务器获取指定的资源 ( 静态的文本、页面、图片视频等 );(安全且幂等)
POST :根据请求负荷(报文body)对指定的资源做出处理;(不安全不幂等)
HTTP协议中:安全指的是请求方法不会破坏服务器上资源,幂等是多次执行相同的操作,结果都是相同的。

HTTP缓存技术

  对于一些具有重复性的 HTTP 请求,如每次请求得到的数据都一样的,可以把这对「请求-响应」的数据都缓存在本地,那么下次就直接读取本地的数据,不必在通过网络获取服务器的响应了。所以,避免发送 HTTP 请求的方法就是通过缓存技术。
  HTTP缓存:强制缓存 和 协商缓存
强制缓存: Cache-Control 一个相对时间; Expires 一个绝对时间
协商缓存: 服务端告知客户端是否可使用缓存的方式就是协商缓存,就是与服务端协商之后,通过协商结果来判断是否使用 本地缓存
两种方式实现协商缓存,一种是基于时间的,一种是基于唯一标识的,主要是第二种好一点:请求头部字段和响应头部中的ETag字段
注:
  协商缓存这两个字段都需要配合强制缓存中 Cache-Control 字段来使用,只有在未能命中强制缓存的时候,才能发起带有协商缓存字段的请求。
用ETag字段实现协商缓存的过程:

  1. 浏览器第一次请求访问服务器资源时,服务器返回资源同时,在Response头部加上 ETag唯一标识(根据当前请求的资源生成的);
  2. 浏览器再次请求资源时,先检查强制缓存是否过期,没过期则直接使用本地缓存,过期会在Request头部加if-None-Match字段,这个字段值就是ETag唯一标识;
  3. 服务器再次收到请求后,会根据请求中的if-None-Match值与当前请求的资源生成的唯一标识进行比较: 相等就返回304Not Modified不会返回资源、不相等则返回200状态码和返回资源并在Response头部加上新的ETag唯一标识;
  4. 浏览器收到304请求响应状态码,就会从本地缓存中加载资源,否则更新资源。

HTTP特性

HTTP/1.1的优点有哪些?

  1. 简单
  2. 灵活和易于扩展
  3. 应用广泛和跨平台

HTTP/1.1缺点有哪些?

  1. 无状态双刃剑:好处时服务器不会记忆HTTP状态,不需要额外资源记录状态信息,能减轻服务器负担;坏处是因为没有记忆能力,在完成有关联性的操作时会非常麻烦; 解决方案: Cookie技术:在客户端第一次请求后,服务器会下发一个装有客户信息的「小贴纸」,后续客户端请求服务器的时候,带上「小贴纸」,服务器就能认得了了;
  2. 明文传输双刃剑:好处是方便,坏处是信息裸奔;
  3. 不安全: 可用HTTPS的方式解决,通过引入SSL/TLS层,在安全上达到极致;

HTTP/1.1性能?

  1. 长连接:只要任意一端没有明确提出断开连接,则保持TCP连接状态
  2. 管道网络传输:同一个TCP里,客户端可发起多个请求,只要第一个请求发出去,不必等其回来就可发第二个请求出去,可减少整体响应时间。服务器必须按照接收请求的顺序发送对这些管道化请求的响应,会产生队头堵塞。
  3. 队头阻塞:

HTTP与HTTPS有哪些区别?

TCP和HTTP网络层之间加入了SSL/TLS安全协议,让报文可以加密传输
HTTP存在 窃听风险、篡改风险、冒充风险
HTTPS通过 混合加密解决窃听风险,摘要算法用于校验数据完整性解决篡改风险,服务器公钥放入数字证书中解决了冒充风险。

  1. 混合加密:对称和非对称加密,对称加密速度快,非对称加密解决密钥交换问题但速度慢
  2. 摘要算法+数字签名:用摘要算法(哈希函数)计算出内容的哈希值(唯一的),如果只用摘要算法的话,可以计算出哈希值保证内容不会被篡改,当年并不能保证【内容+哈希值】不会被中间人替换,因为缺少对客户端收到消息是否来源于服务端的证明。这里就需要用到数字签名算法,非对称加密,主要在于通过【私钥加密,公钥解密】方式来确认消息身份,这种方式对内容的哈希值进行加密。
  3. 数字证书:前面说了可以通过哈希算法保证消息的完整性,通过数字签名来保证消息来源可靠性(能确认消息是由持有私钥的一方发送的);但是缺少身份验证环节,万一公钥私钥是伪造的呢。有个CA数字证书认证机构会弄出一个数字签名出来,公钥放到数字证书中,保证服务器公钥的身份,解决冒充风险。

HTTPS如何建立连接,中间交互了啥?

SSL/TLS协议基本流程:

  1. 客户端向服务器索要并验证服务器的公钥
  2. 双方协商生产 [ 会话密钥 ],然后进行加密通信
    TLS握手有四次通信,不同密钥交换算法,导致流程也不同,有两种常用密钥交换算法:RSA和ECDHE算法
    TLS协议建立的流程:
  3. 客户端发起加密通信请求
  4. 服务端收到请求后给出响应
  5. 客户端回应(从数字证书中取出服务器的公钥,客户和服务端有三个随机数就用双方协商的加密算法生成本次通信的 会话密钥)
  6. 服务端最后回应

CA签发证书的过程:首先把公钥、用途等信息打包后进行Hash计算得到一个值,然后用自个的私钥加密,最后将Certificate Signature 添加在文件证书上,形成数字证书。

客户端校验服务端数字证书过程:首先客户端用同样的Hash算法得到证书Hash值,浏览器收到证书后用CA公钥解密内容得到Hash值后,两个进行比较,相同就冲,不同就拉倒!

证书信任链(为保证根证书的绝对安全性,将根证书隔离的越严格越好)

HTTPS应用数据如何保证完整性

握手协议和记录协议

HTTPS一定安全可靠吗?

  1. 用户点击接受了中间人服务器的证书,那就可以被监控了;
  2. 电脑中病毒后,HTTPS数据会被中间人劫持;
    HTTPS 协议本身到目前为止还是没有任何漏洞的,即使成功进行中间人攻击,本质上是利用了客户端的漏洞(用户点击继续访问或者被恶意导入伪造的根证书),并不是 HTTPS 不够安全。
    可通过HTTPS双向认证笔面中间人抓取数据的问题,双向认证方式,不仅客户端会验证服务端的身份,而且服务端也会验证客户端的身份

HTTP1.1/HTTP2/HTTP/3演变

  HTTP1.1使用长连接该喊了短连接造成的性能开销,也支持管道网络传输;
  HTTP/2协议基于HTTPS的,所以安全性有保障,相比HTTP/1.1有头部压缩、二进制格式、并发传输、服务器主动推送资源。
  HTTP/2解决了HTTP/1队头阻塞问题,但没有解决TCP层面的队头阻塞问题。HTTP/2 是基于 TCP 协议来传输数据的,TCP 是字节流协议,TCP 层必须保证收到的字节数据是完整且连续的,这样内核才会将缓冲区里的数据返回给 HTTP 应用,那么当「前 1 个字节数据」没有到达时,后收到的字节数据只能存放在内核缓冲区里,只有等到这 1 个字节数据到达时,HTTP/2 应用层才能从内核中拿到数据,这就是 HTTP/2 队头阻塞问题。
  一旦发生了丢包现象,就会触发 TCP 的重传机制 ,这样在一个 TCP 连接中的所有的 HTTP 请求都必须等待这个丢了的包被重传回来。

HTTP/3把HTTP下层的TCP协议改成了UDP!(解决HTTP/2队头阻塞问题)
基于QUIC协议可以实现类似TCP的可靠传输,因为他有三个特点

  1. 无队头阻塞:当某个流发生丢包时,只会阻塞这个流,其他流不会受到影响,因此不存在队头阻塞问题;
  2. 更快的连接建立:QUIC协议握手过程只需要 1 RTT
  3. 连接迁移:基于 TCP 传输协议的 HTTP 协议通过四元组(源 IP、源端口、目的 IP、目的端口)确定一条 TCP 连接,当移动设备的网络从 4G 切换到 WIFI 时,意味着 IP 地址变化了,那么就必须要断开连接,然后重新建立连接。给用户的感觉就是网络突然卡顿了一下。QUIC 协议没有用四元组的方式来“绑定”连接,而是通过连接 ID 来标记通信的两个端点,没有丝毫卡顿感,达到了连接迁移的功能。

HTTP1.1如何优化

尽量避免发送HTTP请求

对于有重复性的请求,利用缓存技术

在需要发送HTTP请求时,考虑如何减少请求次数?

  1. 减少重定向请求次数:重定向的工作交由代理服务器完成,就能减少 HTTP 请求次数了
  2. 合并请求:多个访问小文件的请求合并成一个大的请求,虽然传输的总资源还是一样,但是减少请求,也就意味着减少了重复发送的 HTTP 头部。一般浏览器会同时发起 5-6 个请求,每一个请求都是不同的 TCP 连接,那么如果合并了请求,也就会减少 TCP 连接的数量,因而省去了 TCP 握手和慢启动过程耗费的时间。
  3. 延迟发送请求:请求网页时候只获取用户当前看到的页面,用户往下滑动时候再向服务器获取接下来的资源。

减少服务器的HTTP响应的数据大小

  1. 无损压缩:信息不被破坏,还能完全恢复到压缩前的原样;
  2. 有损压缩:将次要的数据舍弃,牺牲质量提高压缩比;

HTTPS怎么优化?

性能损耗:TLS协议握手过程;握手后的对称加密报文传输;

  1. 硬件优化(买好的CPU)
  2. 软件优化:软件升级、协议优化(密钥交换过程优化(ECDHE)、TLS升级(TLS1.2需要2RTT,TLS1.3需要1RTT))
  3. 证书优化:证书传输(ECDSA)、证书验证(CRL,OCSP、OSCP Stapling)
  4. 会话复用Session ID:客户端和服务器首次 TLS 握手连接后,双方会在内存缓存会话密钥,并用唯一的 Session ID 标识,Session ID 和会话密钥相当于 key-value 的关系,但也有缺点。为此出现Session Ticket: 服务器不再缓存每个客户端的会话密钥,而是把缓存的工作交给了客户端,类似于HTTP的Cookie。
    Pre-shared Key:Session ID 和 Session Ticket恢复会话时间(1RTT),LS1.3 使用 Pre-shared Key 会话重用技术,只需要 0 RTT 就可以恢复会话,重连时客户端会把 Ticket 和 HTTP 请求一同发送给服务端。会话重用存在安全问题,有重放攻击风险,所以应对会话密钥设定一个合理的过期时间。

HTTP/2厉害在哪?

  1. 头部压缩 : 静态表编码、动态表编码
  2. 二进制帧
  3. 并发传输
  4. 服务器主动推送资源

HTTP/3来袭

  TCP协议更换为了UDP协议,为保证可靠性,加入了QUIC协议(无队头阻塞、更快的连接建立、连接迁移);
无队头阻塞:QUIC 连接上的多个 Stream 之间并没有依赖,都是独立的,某个流发生丢包了,只会影响该流,其他流不受影响
更快的连接建立:QUIC 内部包含了 TLS,它在自己的帧会携带 TLS 里的“记录”,再加上 QUIC 使用的是 TLS 1.3,因此仅需 1 个 RTT 就可以「同时」完成建立连接与密钥协商,甚至在第二次连接的时候,应用数据包可以和 QUIC 握手信息(连接信息 + TLS 信息)一起发送,达到 0-RTT 的效果
连接迁移:QUIC 协议通过连接 ID 来标记通信的两个端点,客户端和服务器可以各自选择一组 ID 来标记自己,因此即使移动设备的网络变化后,导致 IP 地址变化了,只要仍保有上下文信息(比如连接 ID、TLS 密钥等),就可“无缝”复用原连接,消除重连的成本,没有丝毫卡顿感。

HTTP协议、RPC协议?

纯裸TCP会有 “粘包” 问题,所以需要加入一些自定义的规则,区分消息边界;
区别:服务发现、底层连接形式、传输内容
历史原因:HTTP/2是2015年出来的,那时很多公司用RPC协议多年,没必要换了。

HTTP协议、websocket?

  看起来服务器主动发消息给客户端的场景:使用HTTP不断轮询(有卡顿)、有长轮询(应用场景简单),在用户不感知情况下,服务器将数据推给浏览器的技术就是所谓服务器推送技术;
  考虑到类似网页游戏这种客户端和服务器之间要互相主动发大量数据的场景,所以新的应用层协议WebSocket就被设计出来。
websocket连接的建立:为兼容使用场景,浏览器TCP三次握手后都同意使用HTTP协议先进行一次通信,若是普通请求,那就老样子,若是websocket连接,就在HTTP请求里带一些特殊header头,有升级协议,带随机码啥的。WebSocket只有在建立连接时才用到了HTTP,升级完成之后就跟HTTP没有任何关系了。
TCP协议本身是全双工,但HTTP/1.1是半双工,websocket是全双工;

TCP

TCP基本认识

序列号:解决网络包乱序问题
确认应答号:解决丢包问题
TCP:面向连接、可靠的、基于字节流的
建立一个TCP连接是需要客户端与服务端达成三个信息的共识:
socket:由IP地址合端口号组成
序列号:解决乱序问题
窗口大小:流量控制
TCP和UDP区别

  1. 连接:TCP面向连接,UDP不需要连接
  2. 服务对象:TCP是1对1两点服务,UDP支持1对1、1对多,多对多
  3. 可靠性:TCP是可靠交付数据的,UDP尽最大努力交付,不保证可靠性
  4. 拥塞控制、流量控制:TCP有,UDP没有,即使网络拥堵,也不影响UDP发送速率
  5. 传输方式:TCP流式传输没有边界,UDP是一个一个包传输有边界,但可能会丢包和乱序。
  6. 应用场景:TCP用于FTP文件传输、HTTP/HTTPS等,UDP用于音视频等多媒体通信。

TCP和UDP可使用同一个端口吗?

可以,传输层的「端口号」的作用,是为了区分同一个主机上不同应用程序的数据包。 TCP 和 UDP在内核中是两个完全独立的软件模块。当主机收到数据包后,可在 IP 包头的「协议号」字段知道该数据包是 TCP/UDP,所以可根据这个信息确定送给哪个模块(TCP/UDP)处理,送给 TCP/UDP 模块的报文根据「端口号」确定送给哪个应用程序处理。

TCP三次握手

第三次握手是可以携带数据的,前两次握手是不可以携带数据的

Linux系统中查看TCP状态: netstat -napt

为啥是三次握手而不是两次、四次?

问题可以转换为为什么三次握手才可以初始化 Socket、序列号和窗口大小并建立 TCP 连接?

  1. 三次握手才可以阻止重复历史连接的初始化(主要原因)
    要是客户端收到的SYN+ACK不是自个想要的,那就回一个RST报文释放连接,等新的SYN到达服务端后就正常三次握手。旧的SYN报文就是历史连接。两次握手就无法阻止历史连接,因为没有中间状态给客户端来阻止。
  2. 三次握手才可以 同步双方的初始序列号
    两次握手只保证一方初始序列号能被对方成功接收,不能保证双方的初始序列号都能被确认接收。
  3. 三次握手才可以 避免资源浪费
    若客户端发的SYN在网络中阻塞了,重复多次发送SYN报文,那么服务端在收到请求后就会建立多个冗余无效链接,造成资源浪费。

为啥每次建立TCP连接时,初始化的序列号都要求不一样呢?

  1. 为很大程度防止历史报文被下一个相同四元组的连接接收;(主要原因)
  2. 为安全性,防止黑客伪造的相同序列号的TCP报文被对方接收;

TCP层需要MSS?

MTU:一个网络包的最大长度,以太网中一般为1500字节
MSS:除去IP和TCP头部后,一个网络包所能容纳的TCP数据最大长度
  TCP整个报文都给IP层进行分片会存在隐患,若一个IP分片丢失,整个IP报文的所有分片都得重传。为了达到最佳的传输效能 TCP 协议在建立连接的时候通常要协商双方的 MSS 值,当 TCP 层发现数据超过 MSS 时,则就先会进行分片,如果一个 TCP 分片丢失后,进行重发时也是以 MSS 为单位。

第一次握手丢失发生啥?

  如果客户端迟迟收不到服务端的 SYN-ACK 报文(第二次握手),就会触发「超时重传」机制,重传 SYN 报文,而且重传的 SYN 报文的序列号都是一样的。若一直无响应就断开连接。

第二次握手丢失发生啥?

  1. 客户端就会触发超时重传机制,重传 SYN 报文。
  2. 服务端这边会触发超时重传机制,重传 SYN-ACK 报文

第三次握手丢失了,会发生什么?

服务端那一方迟迟收不到这个确认报文,就会触发超时重传机制,重传 SYN-ACK 报文,直到收到第三次握手,或者达到最大重传次数

SYN攻击 以及避免?

  1. 服务端收到客户端的SYN报文时,会创建一个半连接对象加入道内核的【SYN队列】;
  2. 发送SYN+ACK给客户端,并返回一个ACK报文;
  3. 服务端收到ACK报文后,从【SYN队列】中取出一个半连接对象后创建一个新的连接对象放入【Accept队列】;
  4. 应用通过调用accept() socket接口从【Accept队列】取出连接对象;

SYN 攻击方式最直接的表现就会把 TCP 半连接队列打满,这样当 TCP 半连接队列满了,后续再在收到 SYN 报文就会丢弃,导致客户端无法和服务端建立连接。
避免:增大TCP半连接队列、减少SYN+ACK重传次数

TCP连接断开

每个方向都需要一个 FIN 和一个 ACK,因此通常被称为四次挥手,主动关闭连接的,才有 TIME_WAIT 状态。

为什么需要四次挥手?

服务端通常需要等待完成数据的发送和处理,所以服务端的 ACK 和 FIN 一般都会分开发送,因此是需要四次挥手。但是在特定情况下,四次挥手是可以变成三次挥手的。

第一次挥手丢失了,会发生什么?

第一次挥手丢失了,那么客户端迟迟收不到被动方的 ACK 的话,也就会触发超时重传机制,重传 FIN 报文。

第二次挥手丢失了,会发生什么?

如果服务端的第二次挥手丢失了,客户端就会触发超时重传机制,重传 FIN 报文,直到收到服务端的第二次挥手,或者达到最大的重传次数。

第三次挥手丢失了,会发生什么?

服务端处于 CLOSE_WAIT 状态时,调用了 close 函数,内核就会发出 FIN 报文,同时连接进入 LAST_ACK 状态,等待客户端返回 ACK 来确认连接关闭。如果迟迟收不到这个 ACK,服务端就会重发 FIN 报文。

第四次挥手丢失了,会发生什么?

第四次挥手的 ACK 报文没有到达服务端,服务端就会重发 FIN 报文。客户端在收到第三次挥手后,就会进入 TIME_WAIT 状态,开启时长为 2MSL 的定时器。

为什么 TIME_WAIT 等待的时间是 2MSL?

MSL(报文最大生存时间)。网络中可能存在来自发送方的数据包,当这些发送方的数据包被接收方处理后又会向对方发送响应,所以一来一回需要等待 2 倍的时间。

为什么需要 TIME_WAIT 状态?

主动发起关闭连接的一方,才会有TIME-WAIT状态。原因如下:

  1. 防止历史连接中的数据,被后面相同四元组的连接错误的接收;
  2. 保证「被动关闭连接」的一方,能被正确的关闭;
    作用:等待足够的时间以确保最后的 ACK 能让被动关闭方接收,从而帮助其正常关闭。

TIME_WAIT 过多有什么危害?

  1. 占用系统资源,比如文件描述符、内存资源、CPU 资源、线程资源等;
  2. 占用端口资源,端口资源也是有限;
    如果服务端要避免过多的 TIME_WAIT 状态的连接,就永远不要主动断开连接,让客户端去断开,由分布在各处的客户端去承受 TIME_WAIT。

服务器出现大量 TIME_WAIT 状态的原因有哪些?

TIME_WAIT 状态是主动关闭连接方才会出现的状态,所以如果服务器出现大量的 TIME_WAIT 状态的 TCP 连接,就是说明服务器主动断开了很多 TCP 连接。当出现以下场景时服务端会主动断开连接:

  1. HTTP 没有使用长连接
  2. HTTP 长连接超时
  3. HTTP 长连接的请求数量达到上限

服务器出现大量 CLOSE_WAIT 状态的原因有哪些?

当服务端出现大量 CLOSE_WAIT 状态的连接的时候,说明服务端的程序没有调用 close 函数关闭连接。

如果已经建立了连接,但是客户端突然出现故障了怎么办?

那服务端的TCP一直处于ESTABLISH 状态,占用着系统资源,为解决这种情况TCP搞了个保活机制

如果已经建立了连接,但是服务端的进程崩溃会发生什么?

内核需要回收该进程的所有 TCP 连接资源,于是内核会发送第一次挥手 FIN 报文,后续的挥手过程也都是在内核完成,并不需要进程的参与,所以即使服务端的进程退出了,还是能与客户端完成 TCP 四次挥手的过程

Socket编程

针对TCP如何进行Socket编程 ?

在这里插入图片描述

accept 发生在三次握手的哪一步?

客户端 connect 成功返回是在第二次握手,服务端 accept 成功返回是在三次握手成功之后。

没有 accept,能建立 TCP 连接吗?

可以;accpet 系统调用并不参与 TCP 三次握手过程,它只是负责从 TCP 全连接队列取出一个已经建立连接的 socket,用户层通过这个socket就可以对该 socket 进行读写操作了。

没有 listen,能建立 TCP 连接吗?

可以,客户端是可以自己连自己的形成连接(TCP自连接),也可两个客户端同时向对方发出请求建立连接(TCP同时打开),这两个情况都有个共同点,就是没有服务端参与,也就是没有 listen,就能 TCP 建立连接。

TCP重传、滑动窗口、流量控制、拥塞控制

重传机制

  1. 超时重传
  2. 快速重传
  3. SACK方法 ( 选择性确认,只重传丢失的数据 )
  4. Duplicate SACK

滑动窗口

窗口大小:无需等待确认应答,而可以继续发送数据的最大值。通常这个大小由接收方的窗口大小来决定的,发送方数据大小不能超过接收方的窗口大小。

发送方的滑动窗口:当发送方把数据全部抖一下发送出去后可用窗口大小就为0了,在没收到ACK确认前无法继续发送数据了。当收到之前发送的数据32~36字节的ACK确认应答后,若发送窗口大小无变化,则滑动窗口往右边移动5字节,因为有5字节的数据被应答确认,然后就有5字节变成了可用窗口。

接收方的滑动窗口:接收和发送窗口大小并不完全相等,滑动窗口并不是不变的。比如,当接收方的应用进程读取数据速度非常快的话,接收窗口可很快就空缺出来。那新的接收窗口大小,是通过 TCP 报文中的 Windows 字段来告诉发送方。这个传输过程是存在时延的,所以接收窗口和发送窗口是约等于关系。

流量控制

TCP 提供一种机制可以让「发送方」根据「接收方」的实际接收能力控制发送的数据量,这就是所谓的流量控制。

  1. 操作系统缓冲区与滑动窗口的关系

  2. 窗口关闭
    如果窗口大小为 0 时,就会阻止发送方给接收方传递数据,直到窗口变为非 0 为止,这就是窗口关闭。可能造成死锁。

  3. 糊涂窗口综合症
    如果接收方腾出几个字节并告诉发送方现在有几个字节的窗口,而发送方会义无反顾地发送这几个字节,这就是糊涂窗口综合症。

拥塞控制

  在网络出现拥堵时,如果继续发送大量数据包,可能会导致数据包时延、丢失等,这时 TCP 就会重传数据,但是一重传就会导致网络的负担更重,于是会导致更大的延迟以及更多的丢包,这个情况就会进入恶性循环被不断地放大。拥塞控制的目的就是避免「发送方」的数据填满整个网络。
拥塞窗口 cwnd是发送方维护的一个的状态变量,它会根据网络的拥塞程度动态变化的。

  1. 慢启动
      一点一点的提高发送数据包的数量,当发送方每收到一个 ACK,拥塞窗口 cwnd 的大小就会加 1。发包的个数是 指数性的增长 直到到达慢启动门限ssthresh状态变量,当拥塞窗口大小>=ssthresh时,就用拥塞避免算法
  2. 拥塞避免算法
      每当收到一个 ACK 时,cwnd 增加 1/cwnd。拥塞避免算法就是将原本慢启动算法的指数增长变成了线性增长,还是增长阶段,但是增长速度缓慢了一些。就这么一直增长着后,网络就会慢慢进入了拥塞的状况了,于是就会出现丢包现象,这时就需要对丢失的数据包进行重传。当触发了重传机制,也就进入了拥塞发生算法
  3. 拥塞发生
      网络出现拥塞,也就是会发生数据包重传:超时重传、快速重传
    超时重传:使用拥塞发生算法时,ssthresh设为cwnd/2,cwnd 重置为1,有种一朝回到解放前的感觉,然后重新开始慢启动
    快速重传:当接收方发现丢了一个中间包的时候,发送三次前一个包的 ACK,于是发送端就会快速地重传,不必等待超时再重传,TCP 认为这种情况不严重,因为大部分没丢,只丢了一小部分。所以cwnd = cwnd/2,ssthresh = cwnd。进入快速恢复算法
  4. 快速恢复
      快速重传和快速恢复算法一般同时使用,快速恢复算法是认为,你还能收到 3 个重复 ACK 说明网络也不那么糟糕,所以没有必要像 RTO 超时那么强烈。

如何理解TCP面向字节流协议、UDP面向报文协议?

UDP:用户消息通过UDP协议传输时,操作系统不会对消息进行拆分,发出的UDP报文中数据部分是完整的用户消息,每个UDP报文就是一个用户消息的边界。
TCP:通过TCP协议传输时,消息可能会被操作系统分组成多个的TCP报文,我们不能认为一个用户消息对应一个TCP报文,所以TCP时面向字节流的协议。

解决粘包?

  1. 固定长度的消息
  2. 特殊字符作为边界
  3. 自定义消息结构

HTTP的Keep-Alive和TCP的Keep-Alive?

  HTTP的keep-alive是由应用层(用户态)实现的,是HTTP长连接(只要任意一端没有明确提出断开连接,就保持TCP连接状态)。
  TCP的keep-alive由TCP层(内核态)实现的,是TCP保活机制(若两端TCP连接没有数据交互,达到触发TCP保活机制条件,那内核里的TCP协议栈会发送探测报文)
  若对端程序正常工作,当TCP保活的探测报文发送给对端,对端就正常响应,TCP保活时间会被重置,等下一个TCP保活时间的到来。若对端主机宕机,或对端由于其他原因导致报文不可达,当TCP保活的探测报文发送给对端后,没有响应,连续几次达到保活探测次数后,TCP会报告该TCP连接已经死亡。

TCP协议缺陷

  1. 升级TCP工作很困难;
  2. TCP建立连接的延迟;(TCP三次握手后还需经过TLS四次握手才能进行HTTP数据传输,在一定程序上增加了数据传输的延迟)
  3. TCP存在队头阻塞问题;(必须保证收到的字节数据是完整且有序的)
  4. 网络迁移需要重新建立TCP连接;(移动设备从4G切换到wifi时,ip地址变化了就得断开连接重新建立TCP连接,而建立连接包含TCP三次握手+TLS四次握手的时延+TCP慢启动的减速过程,给用户感觉卡了一下)

基于UDP协议实现可靠传输

QUIC如何实现可靠传输

基于 UDP 实现的可靠传输协议,那么就要在应用层下功夫,也就是要设计好协议的头部字段

  1. Packet Header(Long Packet Header用于首次建立连接, Short Packet Header用于日常传输数据)
  2. QUIC Frame Header : 一个Packet报文中可以存放多个QUIC Frame,QUIC通过单向递增的Packet Number,配合Stream ID与Offset字段信息,可以支持乱序确认而不影响数据包的正确组装,摆脱了TCP必须按顺序确认应答ACK的限制,解决了TCP因某个数据包重传而阻塞后续所有待发送数据包的问题。

QUIC 是如何解决 TCP 队头阻塞问题的?

  1. TCP 队头阻塞的问题
    其实就是接收窗口的队头阻塞问题。当接收窗口收到有序数据时,接收窗口才能往前滑动,然后那些已经接收并且被确认的「有序」数据就可以被应用层读取。导致接收窗口的队头阻塞问题,是因为 TCP 必须按序处理数据,也就是 TCP 层为了保证数据的有序性,只有在处理完有序的数据后,滑动窗口才能往前滑动,否则就停留
  2. HTTP/2的队头阻塞
    HTTP/2 多个 Stream 请求都是在一条 TCP 连接上传输,这意味着多个 Stream 共用同一个 TCP 滑动窗口,那么当发生数据丢失,滑动窗口是无法往前移动的,此时就会阻塞住所有的 HTTP 请求,这属于 TCP 层队头阻塞。
  3. 没有队头阻塞的QUIC
    QUIC给每一个Stream都分配了一个独立的滑动窗口,这样使得一个连接上的多个Stream之间没有依赖关系,都是相互独立的,各自控制的滑动窗口。

QUIC咋做流量控制?

  1. 通过 window_update 帧告诉对端自己可以接收的字节数,这样发送方就不会发送超过这个数量的数据。
  2. 通过 BlockFrame 告诉对端由于流量控制被阻塞了,无法发送数据。
      QUIC 的 每个 Stream 都有各自的滑动窗口,不同 Stream 互相独立,队头的 Stream A 被阻塞后,不妨碍 StreamB、C的读取
    QUIC实现了两种级别的流量控制,分别为Stream和Connection两种:
  3. Stream级别:Stream 可以认为就是一条 HTTP 请求,每个 Stream 都有独立的滑动窗口,所以每个 Stream 都可以做流量控制,防止单个 Stream 消耗连接(Connection)的全部接收缓冲。
  4. Connection级别:限制连接中所有 Stream 相加起来的总字节数,防止发送方超过连接的缓冲容量。

QUIC 对拥塞控制改进

  QUIC 协议当前默认使用了 TCP 的 Cubic 拥塞控制算法( 我们熟知的慢开始、拥塞避免、快重传、快恢复策略 ),相当于将 TCP 的拥塞控制算法照搬过来了。

  1. QUIC 可以随浏览器更新,QUIC 的拥塞控制算法就可以有较快的迭代速度;
  2. QUIC 处于应用层,所以就可以针对不同的应用设置不同的拥塞控制算法,这样灵活性就很高了;

QUIC 更快的连接建立

  HTTP/3 在传输数据前虽然需要 QUIC 协议握手,这个握手过程只需要 1 RTT,握手的目的是为确认双方的「连接 ID」,连接迁移就是基于连接 ID 实现的。QUIC 内部包含了 TLS,它在自己的帧会携带 TLS 里的“记录”,再加上 QUIC 使用的是 TLS1.3,因此仅需 1 个 RTT 就可以「同时」完成建立连接与密钥协商,甚至在第二次连接的时候,应用数据包可以和QUIC握手信息( 连接信息 + TLS信息 )一起发送,达到0-RTT的效果。

QUIC 是如何迁移连接的?

  TCP协议因为慢启动啥的时延啥的给用户感觉卡顿了一下,QUIC 协议没有用四元组的方式来“绑定”连接,而是通过连接 ID来标记通信的两个端点,客户端和服务器可以各自选择一组 ID 来标记自己,因此即使移动设备的网络变化后,导致 IP 地址变化了,只要仍保有上下文信息(比如连接 ID、TLS 密钥等),就可以“无缝”地复用原连接,消除重连的成本,没有丝毫卡顿感,达到了连接迁移的功能。

用了TCP协议,数据一定不会丢吗?

  1. 数据从发送端到接收端,链路很长,任何一个地方都可能发生丢包,几乎丢包不可避免。
  2. 大部分时候TCP重传机制保证了消息可靠性
  3. 发现服务异常时候,若接口延时很高总是失败,可用ping或mtr看是不是中间链路发生了丢包
  4. TCP只保证传输层的消息可靠性,并不保证应用层的消息可靠性,若我们还想保证应用层的消息可靠性,就需要应用层自己去实现逻辑做保证。

以上内容均来自小林coding,若有侵权,联系删除!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值