原稿:语雀 · 计算机网络 · 原目录:Web & 浏览器 › 计算机网络

有时候感觉自己不是能写出《劝退宝典》的人,很多东西已经完全忘干净了🆒

网络协议栈

所有各层协议合称协议栈,因特网协议栈有5层,ISO/OSI模型有7层

  • PDU(Protocol Data Unit):协议数据单元,是指对等层次之间传递的数据单位
计算机网络 配图

应用层

支持网络程序,是网络程序及其应用层协议存留处

  • PDU: message
  • FTP, SMTP, HTTP
image.png
image.png

传输层

在程序端点间传输应用层message

  • PDU:  segment
  • TCP, UDP

网络层

将称为数据报(datagram)的网络层分组从一台主机移动到另一台

  • PDU: datagram
  • IP

链路层

在相邻网络节点间转递数据,其上的分组为帧(frame)

  • PDU: frame
  • Ethernet, 802.111, PPP

物理层

负责将frame中的bit运输到相邻网络元素

  • PDU: bits

I S

O

表示层

使通信的app可解释交换数据的含义

会话层

提供数据交换和定界与同步功能,包括建立check point和恢复


TCP——面向连接的传输

TCP 概览

报文段

计算机网络 配图

组成

image.png
  • 发送方:发送缓存、变量和进程 socket
  • 接收方:接收缓存,变量和进程 socket

两台host之间的网络元素(routers,switchers)没有为连接分配cache和变量

特点

  • 面向连接的可靠传输:三次握手、四次挥手,传输可靠有序的字节流
  • 一一对应:一个 sender,一个 receiver
  • 缓冲:sender 与 receiver 都有缓存区
  • 全双工通信:在一条 TCP 连接中的双向数据流

TCP 连接管理

  • 三次握手
image.png

第一次——客户端请求连接: 

客户端随机初始化序号(client_isn),置于 TCP 首部的 seq 字段中,同时把 SYN 标志位置为 1 。把第一个 SYN 报文发送给服务端,该报文不包含应用层数据,之后客户端处于 SYN-SENT 状态

SYN=1

seq=client_isn

第二步——服务端确认 & 请求连接:

 服务端收到客户端的 SYN 报文后,随机初始化序号(server_isn)填入 TCP 首部 seq 中,设置 ACK=1 ,ack=client_isn + 1,接着把 SYN 标志置为 1。把该报文发给客户端,该报文也不包含应用层数据,之后服务端处于 SYN-RCVD 状态

SYN=1

ACK=1

seq=server_isn

ack=client_isn+1

ACK 和 ack:前者用于标注当前报文段的性质(SYN、ACK、FIN),后者用于向发送方确认已经收到的分组

第三步——客户端确认 & 传输数据: 

客户端收到报文后需要发送确认,ACK=1,ack=server_isn + 1 ,seq=client_isn + 1 ,最后把报文发送给服务端,连接已经建立,这次报文可以携带客户到服务器的数据,之后客户端处于 ESTABLISHED 。服务器收到客户端的应答报文后,也进入 ESTABLISHED 状态

ACK=1

seq=client_isn+1

ack=server_isn+1

- 四次挥手
image.png

第一次——客户端请求断开:  开始双方都处于 ESTABLISHED 状态。当客户端想要断开连接:客户端发出连接释放报文段,置 FIN=1,seq=u,进入FIN-WAIT-1状态

FIN=1

seq=u

第二次——服务端确认请求:  服务器收到客户端报文后,发出确认报文段:ACK=1,ack=u+1,seq=v,进入CLOSE-WAIT状态。客户端收到服务器确认结果后,进入FIN-WAIT-2状态。

ACK=1

ack=u+1 seq=v

第三次——服务端请求断开:  当服务器完成所有发送后,发送连接释放报文段:FIN=1,ACK=1,ack=u+1,seq=w,服务器进入LAST-ACK(最后确认态)

FIN=1

ACK=1

ack=u+1

seq=w

第四步——客户端确认请求:  客户端收到请求,发送确认报文段:ACK=1,ack=w+1,seq=u+1,进入TIME-WAIT(时间等待)。经过2个最长报文段寿命后,客户端CLOSE;服务器收到确认后,立刻进入CLOSE状态

ACK=1

ack=w+1

seq=u+1

【问题1】为什么是三次握手,不能仅有两次?

假如不采用三次握手,那么只要 server 发出确认,新的建立就连接了,但当该  ACK 错误/冗余时,client 不会理睬 server的确认信息,也不会向服务端发送任何数据。但是server认为新的连接已经建立起来了,并一直等待 client 发来数据,这样,server的很多资源就没白白浪费掉了,采用三次握手就是为了防止这种情况的发生, server 会因为收不到确认的报文,就知道 client 并没有建立连接

【问题2】为什么连接的时候是三次握手,关闭的时候却是四次握手?

因为当 server 收到 client 的 SYN 连接请求报文后,可以直接发送 SYN+ACK 报文。但是关闭连接时,当 server 收到 FIN 报文时,可能当前仍处于传输状态,并不会立即关闭 SOCKET ,只能先回复一个 ACK 报文,只有 server 确认所有的报文都发送完,才能发送 FIN 报文,因此不能一起发送。故需要四步握手。

【问题3】为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?

必须认为网络是不可靠的,有可能最后一个 ACK 丢失。所以 TIME_WAIT 状态就是用来重发可能丢失的 ACK 报文。2MSL 就是一个发送和一个回复所需的最大时间。如果直到2MSL,Client都没有再次收到FIN,那么Client 推断 ACK 已经被成功接收,则结束 TCP 连接。

可靠数据传输

网络层的 IP 服务不可靠,TCP 需要在不可靠之上建立可靠数据传输服务:确保一个进程从其接收缓存中读出的是无损、有序、非冗余的数据流。

rdt 实现的主要机制有:

  • 校验和(checksum):检测分组的比特错误,接收方会丢弃出错的分组
  • 计时器(timer):为了应对分组/ ACK 丢失或延迟,在 timeout 时重传分组
  • 序号(seq):为从发送方流向接收方的分组按序编号,接收方因此可以检测到分组丢失
  • 确认号(ack):接收方告诉发送方一个或一组分组已经被正确接收
  • 窗口、流水线:RDT3.0 的停等协议保证了可靠传输,但性能孱弱,因为要求确认一个分组后才能发送下一个。流水线机制允许一次发送多个分组,提高了发送方的利用率,接收方则可缓存分组
  • 流水线机制可能遇到缓存溢出问题,因此有了"流量控制"
  • 为了包装流水线的传输可靠性问题,提出了 GBR 与 SR 算法

GBN

  1. 顺序性:对于sender,必须确认收到 [base] 分组被正确接收才能窗口右移;对于 receiver,必须接收 [expectseq] 分组才能返回 ACK 并 seq++
  2. 按窗口重发:当 timeout 时,无论处于 sender [base]~[seq-1] 的分组是否能正确到达,重发所有(回退)
  3. 积累确认:对序号为 n 的分组确认时,表明接收方对 n 和 n 之前所有的分组都正确接收
  4. 冗余/错误分组:无操作

SR

  1. 部分顺序性:sender 只有收到窗口中序号最小分组的 ACK 后才窗口右移;receiver 对于在窗口中的任意分组,正确接收后返回 ACK,不用考虑顺序
  2. 重发最小未确认分组:当 timeout 后,重发当前最小未确认的分组,重启计时器
  3. 非积累确认
  4. 冗余/错误分组:无操作

TCP 流量控制

参考链接:TCP协议的滑动窗口具体是怎样控制流量的? - wuxinliulei的回答 - 知乎

背景

由于TCP在 sender/receiver 都具有buffer,为了避免处理速度不一致导致 receiver buffer溢出,数据丢失,需要进行流控,使得两端速度相一致

实现

image.png

TCP 让 sender 维护一个接收窗口(receiver window),用于提示 receiver 还有多少 buffer 可用,且全双工通信使得两端发送方各自维护一个窗口,对于发送方,即发送窗口

场景

A发送文件给B:B为连接分配RcvBuffer,B上进程定期从中读取数据,定义变量:

  • LastByteRead:B从 buffer 中读出的 data flow 最后一个byte编号
  • LastByteRcvd:从网络到达且放入B接收缓存中数据流的最后一个 Byte 编号

为了不溢出,必须保证(rwnd标识接收窗口)

LastByteRcvd-LastByteRead≤RcvBuffer

rwnd = RcvBuffer-[LastByteRcvd-LastByteRead]

TCP 拥塞控制

背景

拥塞现象是指到达通信子网中某一部分的分组数量过多,使得该部分网络来不及处理,以致引起这部分乃至整个网络性能下降的现象,严重时甚至会导致网络通信死锁

拥塞控制是链路上的控制(堵车发生在路上);流量控制是S/R端的控制

image.png

慢启动

  • 初始:给 cwnd 起始设置为1MSS(最大报文段长度)的较小值,使得初始速率为MSS/RTT
  • 传输:之后每次 sender 确认一个 seg 后,把 cwnd 增加一个 MSS,则 sender 的 cwnd 每次翻倍
  • 结束:拥塞后,有三种结束慢启动增长 cwnd 的方式
  1. timeout 标识的拥塞(说明路上确实堵):sender 把 cwnd 重置为1,重启慢启动过程;同时设置 ssthresh 为 cwnd/2
  2. 当 cwnd==ssthresh (慢启动阈值),结束慢启动,令 sstresh=cwnd/2,拥塞避免
  3. 如果发生快速重传(Fast retransmit),快速恢复

拥塞

避免

  • 传输:如果进入拥塞避免,此时如果 cwnd 继续翻倍,很容易又进入拥塞,因此采用每次 cwnd增长一个MSS
  • 结束:丢包事件发生
  1. timeout 标识的拥塞:同上,cwnd=1,sstresh=cwnd/2,重启慢启动
  2. 当被3冗余ACK触发(说明只是出错,不一定拥塞),则反应不应剧烈,进入快速恢复

快速

恢复

  • 快速恢复:立刻重传丢失的seg,cwnd 减半,每个冗余 ACK 使 cwnd++,最终 cwnd=1/2cwnd+3,sstresh=1/2cwnd,进入拥塞避免
  • 如果重传未抵达就发生 timeout ,则 cwnd=1,sstresh=cwnd/2,进入慢启动

UDP——无连接传输

特征

  • 无连接的
  • 没有 s/r 之间的握手;
  • 尽力而为的传输
  • 每个 UDP seg 都独立于其他 seg 被处理
  • 丢包,乱序
  • 简单
  • header 更小
  • 无拥塞控制
image.png

用于

  • 适合 loss tolerant 以及 rate sensative 的程序,如:流媒体,DNS
  • 广播与组播:没有建立连接的情况下只能使用 UDP

对比

TCP

  • 面向连接:只能一对一
  • 可靠数据传输:checksum、timer、seq、ACK、窗口与流水线
  • 流控,拥控

UDP

  • 无连接:可以一对一、一对多
  • 尽力而为的传输:只提供 checksum

DNS解析

域名系统(Domain Name System,DNS)是互联网的一项服务。它作为将域名和IP地址相互映射的一个分布式数据库,能够使人更方便地访问互联网。本地DNS协议作为应用层协议,基于运输层的UDP之上,使用53端口

DNS server分层

dns.png
- Root name servers:根域名服务器,提供TLD服务器的IP地址 - TLD, Top-level domain servers:顶级域名服务器,对于如com/org/net/edu/gov等顶级域和国家域都有TLD服务器,提供authoritative servers的IP地址 - Authoritative DNS servers:权威DNS服务器,在Internet上有公共可访问主机的组织机构需提供公众可访问的DNS记录,用以映射IP地址,组织机构需实现自己的权威DNS服务器来实现保存记录 - local DNS serves:本地DNS服务器,并不严格属于分层结构。每个ISP有一台local server,当用户host发出DNS query时,query被发送到本地server(更像是代理,实现请求的转发)

迭代 DNS 查询

场景:纽约大学计算机系主机cis.poly.edu想知道主机gaia.cs.umass.edu的IP地址,且已知NYU计算机系的本地DNS服务器dns.poly.edu

  1. cis.poly.edu首先向本地dns.poly.edu发送一个查询msg,其中包含要查询的主机名gaia.cs.umass.edu
  2. local server发送msg至root server
  3. root server发现edu前缀并把负责edu的TLD server的IP地址列表返回给local server
  4. local server向TLD发送msg
  5. TLD注意到umass前缀,返回对应机构AD server IP地址列表给local server
  6. local server向机构的AD server(dns.cs.umass.edu)发送msg
  7. 对应AD server用查询到的gaia.cs.umass.edu对应IP响应
  8. local server返回结果IP地址给host
迭代.png

递归 DNS 查询

  1. 用户host向local server发送查询msg,其中包含要转换的主机名
  2. local server向root server发送msg
  3. root server根据edu前缀发送msg至负责edu的TLD
  4. TLD根据umass.edu前缀发送msg至负责的AD server
  5. AD server将msg中主机名对应的IP地址发送回TLD
  6. TLD返回IP给root server
  7. root返回IP给local server
  8. local server返回转换结果给host
递归.png

实际应用中,caching 技术的存在使得迭代式 DNS 查询被广泛使用,caching 技术能把任何映射缓存在本地,比如 dns.poly.edu 从 RD/TLD/AD 得到的映射结果都会被保存在 local DNS server,此时内网中

  • 一台host查询不同域名:第一次要转换a.edu完成后,第二次查询b.edu的IP地址,负责edu的TLD IP地址结果已经在本地,可直接从中查询下级权威server IP
  • 两台host查询相同域名:内网第一台host查询a.edu后本地server缓存其IP,第二台host查询a.edu,可直接返回结果

通常在向 DNS 根服务器查询前会搜索以下缓存:

  • 浏览器缓存:当用户通过浏览器访问某域名时,浏览器首先会在自己的缓存中查找是否有该域名对应的IP地址
  • 系统缓存:当浏览器缓存中无对应 IP 则会自动检查用户计算机 Hosts 文件 DNS 缓存是否有该域名对应 IP
  • 路由器缓存:当浏览器及系统缓存中均无域名对应 IP 则进入路由器缓存检查,以上均为客服端的 DNS 缓存
  • ISP(互联网服务提供商)DNS缓存:当在用户客服端查找不到域名对应IP地址,则将进入 ISP DNS 缓存中进行查询。比如你用的是电信的网络,则会进入电信的 DNS 缓存服务器中进行查找

HTTP

参考链接:从输入URL到页面加载的过程?如何由一道题完善自己的前端知识体系!

用户和服务器之间的信息传递依赖http request和http response,前端页面的加载也是这样,因此http协议是前端学习中重要的部分

HTTP 报文结构

报文一般包括了:通用头部、请求/响应头部、请求/响应体,通用头部格式如下

Request Url: 请求的web服务器地址
Request Method: 请求方式(Get、POST、OPTIONS、PUT、HEAD、DELETE、CONNECT、TRACE)
    * GET       获取资源
    * POST      传输资源
    * PUT       更新资源
    * DELETE    删除资源
    * HEAD      获得报文首部
Status Code: 请求的返回状态码,如200代表成功
Remote Address: 请求的远程服务器地址(会转为IP)
Referrer Policy: 来源页策略
image.png

GET/POST 对比

GET

POST

语义

从指定的资源请求数据

向指定的资源提交要被处理的数据

传输

- GET将请求的数据附在 URL 后通过地址栏传输 - 浏览器会把 header 和 data 一并发送出去,成功则服务器响应 200
- POST 将参数放在 request body 通过报文传输 - 浏览器先发送 header,服务器响应 100 continue,浏览器再发送 data ,成功则服务器响应 200

缓存

- 请求会被主动缓存 - 可携带参数被存为书签