详解计算机网络
本文是在阅读JavaGuide关于计算机网络相关内容时的个人整理;
请移步:https://javaguide.cn/cs-basics/network/osi-and-tcp-ip-model.html
OSI
七层模型
很清晰、理论完整,但是太复杂且不适用,所以更多使用tcp/ip协议
- 应用层:为用户提供了与网络进行交互的接口;
- 表示层:进行一些数据处理,例如加密解密、编码解码、压缩和解压缩
- 会话层:管理应用程序之间的会话
- 传输层:为会话之间的通信提供可靠的数据传输
- 网络层:IP数据包在传输时的路由和寻址
- 链路层:对数据帧进行编码、对传输的误差进行纠正
- 物理层:传输比特流数据
TCP/IP四层模型
应用层
应用层:以报文为数据单元,使得应用程序之间进行信息交换
常见协议:
基于TCP
- HTTP协议(HTTPs):基于 TCP 协议,是一种用于传输超文本和多媒体内容的协议,为 Web 浏览器与 Web 服务器之间的通信而设计的
- Websocket协议:客户端和服务端可以同时发送或接收,基于 TCP 连接的全双工通信,通过心跳机制来保持 WebSocket 连接的稳定性和活跃性
- SMTP协议(简单邮件传输(发送)协议)、IMAP/POP3协议(负责邮件接收的协议)
- FTP协议:文件传输,使用两条tcp连接,一条用于传输控制信息,一条用于数据传送;不安全,SFTP安全
- SSH协议:通过加密和认证机制实现安全的访问和文件传输等业务;Telnet协议:用于终端登录服务器,明文传输不安全
基于UDP
- RTP协议⚠️、WebRTC⚠️
传输层
传输层:负责向两台终端设备进程之间的通信提供通用的数据传输服务。
TCP协议的三次握手和四次挥手:面向连接的、可靠的
UDP协议:无连接的、尽力的
网络层
网络层:网络层负责为分组交换网上的不同主机提供通信服务
封装成IP数据包,解析IP地址,选择合适的路由
常见协议:IP协议(定义数据包的格式、对数据包进行路由和寻址)、ARP协议(网络层地址和链路层地址之间的转换问题)、NAT协议(网络地址转换,内部网到外部网)、ICMP协议⚠️、OSPF协议⚠️、RIP协议⚠️
网络接口层
网络接口层:把IP数据包组装成帧,并在相邻计算机节点之间传输比特流,并提供差错检测和修复等等
HTTP相关
HTTP1.0和1.1
- 缓存:见缓存
- 长连接和短连接:HTTP1.0使用短连接,每次HTTP操作都需要建立tcp连接,会导致握手挥手报文大量占据带宽;长连接可以设置超时时间,减少保持tcp连接的资源浪费。
- Host头处理⚠️
- 带宽优化:加入
Range
头部,可以请求**数据(只能是字节型)**的一部分,支持断点续传,例如下载文件到一半
1 | # 请求:获取一个文件的前 1024 个字节 |
HTTP和HTTPS
HTTP(明文传输, 没有状态):默认端口80,规范浏览器和服务器端的行为。传输的都是明文,不安全。
无状态(stateless)协议,服务器不维护任何有关客户端过去所发请求的消息,有状态协议会更加复杂,需要维护状态(历史信息),而且如果客户或服务器失效,会产生状态的不一致,解决这种不一致的代价更高。
HTTPS(加密传输, 证书认证):默认端口号是 443。额外使用 SSL/TLS 协议用作加密和安全认证。
先使用非对称加密传输对称加密的密钥,来保证密钥的安全性;再进行对称加密的通信。
可能会存在以下使用诈包的攻击手段,所以服务器得进行第三方实名认证,这个就是证书(CA, Certificate Authority)的作用
图源:JavaGuide
HTTP缓存
强制缓存
强制缓存优先于协商缓存进行
HTTP1.0使用Expires,它存储一个过期时间,如果在这个时间内就说明缓存有效,但是依赖于浏览器时间
HTTP1.1使用cache-control字段,有6个字段,常用的是max-age表示缓存的有效时间,例如
Cache-Control: max-age=10
cache-control字段:
- max-age决定客户端资源被缓存多久。
- s-maxage决定代理服务器缓存的时长。
- no-cache表示是强制进行协商缓存。
- no-store是表示禁止任何缓存策略。
- public表示资源即可以被浏览器缓存也可以被代理服务器缓存。
- private表示资源只能被浏览器缓存。
协商缓存
需要向服务器发起请求进行协商,由服务器决定是否使用缓存
- HTTP1.0使用Last-Modified / If-Modified-Since
If-Modified-Since是客户端再次发起该请求时,携带上次请求返回的Last-Modified值,通过此字段值告诉服务器该资源上次请求返回的最后被修改时间。服务器收到该请求,发现请求头含有If-Modified-Since字段,则会根据If-Modified-Since的字段值与该资源在服务器的最后被修改时间做对比,若服务器的资源最后被修改时间大于If-Modified-Since的字段值,则重新返回资源,状态码为200;否则则返回304,代表资源无更新,可继续使用缓存文件;
- HTTP1.1使用Etag / If-None-Match
If-None-Match是客户端再次发起该请求时,携带上次请求返回的唯一标识Etag值,通过此字段值告诉服务器该资源上次请求返回的唯一标识值。服务器收到该请求后,发现该请求头中含有If-None-Match,则会根据If-None-Match的字段值与该资源在服务器的Etag值做对比,一致则返回304,代表资源无更新,继续使用缓存文件;不一致则重新返回资源文件,状态码为200;
常见状态码
- 1xx(临时响应):表示临时响应并需要请求者继续执行操作的状态码。
101:切换协议,切换到更高级的协议,例如HTTP新版
- 2xx(成功):表示成功处理了请求的状态码。
201:请求成功创建一个或多个新的资源
204:请求成功,但没有结果返回(不看重请求结果,只关心是否完成)
206:请求一部分资源,成功响应一部分资源(HTTP1.1断点续传)
- 3xx(重定向):要完成请求,需要进一步操作。通常,这些状态码用来重定向。
301:Moved Permanently,资源被永久重定向。比如网站的网址被更换。
- 4xx(客户端请求错误)
400 Bad Request:发送的 HTTP 请求存在问题。比如请求参数不合法、请求方法错误。
401 Unauthorized:未认证却请求需要认证之后才能访问的资源。
403 Forbidden:直接拒绝 HTTP 请求,不处理。一般用来针对非法请求。
404 Not Found:你请求的资源未在服务端找到。比如你请求某个用户的信息,服务端并没有找到指定的用户。
409 Conflict:表示请求的资源与服务端当前的状态存在冲突,请求无法被处理。
- 5xx(服务器错误)
500 Internal Server Error:服务端出问题了(通常是服务端出 Bug 了)。比如你服务端处理请求的时候突然抛出异常,但是异常并未在服务端被正确处理。
502 Bad Gateway:我们的网关将请求转发到服务端,但是服务端返回的却是一个错误的响应,即网关正常运行,但是网关得到的响应是错误的。
TCP相关
可靠性保证
- 基于数据块传输:分割成数据块(报文段)再给网络层,网络层也可能进一步分割再形成ip数据包;
- 报文段序列号可以用来重新排序和去重;
- 报文段包含首部和数据,接收后会进行校验和,确保数据没有发生差错;
- 流量控制和拥塞控制
访问网页的全过程
- DNS解析,得到IP地址
- 根据IP地址建立TCP连接
- 在TCP连接上发送HTTP请求报文
- 服务器处理请求,返回HTTP响应
- 解析响应体中HTML代码并渲染
- 对HTML中其他需要的资源再次发起请求
- 可以主动关闭TCP连接,或等待服务器关闭
ARQ协议
- 停止等待ARQ协议(这个没有用到滑动窗口协议)
每发完一个数据包就停止发送,等待对方确认(回复 ACK);如果过了一段时间(超时时间后),还是没有收到 ACK 确认,说明没有发送成功,需要重新发送,直到收到确认后再发下一个数据包。
1.1. 发送的数据包丢了:设置一个定时器,自动重传;
1.2. 确认信息丢了or迟到:发送方没收到确认信息,重传,重复的信息直接丢弃。
- 连续ARQ协议(引入滑动窗口),位于发送窗口内的分组可以连续发送出去,而不需要等待对方确认。
2.1. 接收方累计确认(对最后一个数据包发送确认),信道利用率高;
2.2. 滑动窗口中间某个丢了,需要把丢失的后续都传一遍,即Go-Back-N。
重传机制
⚠️参考:知乎专栏
流量控制
为了控制发送方发送速率,接收方来得及接收和处理;客户端和服务端各自维护发送窗口和接收窗口
滑动窗口:针对报文段的划分方式,大小是根据接收端处理数据的速度动态调整的;tcp三次握手的时候会协调出窗口的大小
为什么这种机制能做到流量控制?为发送和确认的异步性提供了缓冲(又快又慢)
- 快:不仅得发送,还得确认接受,这样就不用阻塞在等待确认上了,可以先发送多个然后一起等待确认;
- 慢:如果一直不确认累积一定数目,就会不发送;只有确认才能让滑动窗口移动;
图源:JavaGuide
拥塞控制
防止过多的数据注入到网络中,维护一个拥塞窗口cwnd,在实际使用中会选取滑动窗口和拥塞窗口的最小值
慢开始和拥塞避免
tcp协议在一开始发送数据时,会让拥塞窗口从小到大倍数增长,即每经过一个传播轮次RTT,cwnd加倍;
但是后续不可能增大这么快,所以等到达阈值后,会使用每经过一个传播轮次RTT,cwnd+1的方式;
快重传和快恢复
FRR-fast retransmit and recovery
- 如果没有 FRR,当数据包丢失了,TCP 将会使用定时器来要求传输暂停。在暂停的这段时间内,没有新的或复制的数据包被发送。
- 有了 FRR,当接收机接收到一个不按顺序的数据段(例如接收了1 3),它会立即给发送机发送一个重复确认(此时依然正常接收其他数据包,例如接收1 3 4)。如果发送机接收到三个重复确认(如果是1个,可能把网络延迟给误判成丢包了),它会假定确认件指出的数据段丢失了,并立即重传这些丢失的数据段。
- 快重传:指接收方接收到三个重复确认,此时立即重传对应序列的报文段;
- 快恢复:发生快重传时,把阈值ssthresh、拥塞窗口cwnd都缩小到当前cwnd的一半,并切换到拥塞避免算法(每经过一个传播轮次RTT,cwnd+1)
图源:王道考研
三次握手
先总说:1. 客户端发送数据包等待服务端确认,2. 服务端确认的同时,也需要客户端确认能否收到自己的数据;3. 客户端确认能收到服务端的数据
第一次握手,发送端首先发送一个带SYN(synchronize)标志的数据包给接收方,第一次的seq序列号是随机产生的,这样是为了网络安全,如果不是随机产生初始序列号,黑客将会以很容易的方式获取到你与其他主机之间的初始化序列号,并且伪造序列号进行攻击
第二次握手,接收端收到后,回传一个带有SYN/ACK(acknowledgement)标志的数据包以示传达确认信息;SYN 是为了告诉发送端,发送方到接收方的通道没问题;ACK 用来验证接收方到发送方的通道没问题
第三次握手,发送端再回传一个带ACK标志的数据包,代表握手结束,若在握手某个过程中某个阶段莫名中断,TCP协议会再次以相同的顺序发送相同的数据包
图源:稀土掘金
四次挥手
客户端发送一个 FIN,用来关闭服务端到客户端的数据传送
服务端收到这个 FIN,它发回一个 ACK,确认序号为收到的序号加1 。和 SYN 一样,一个 FIN 将占用一个序号
服务端关闭与客户端的连接,发送一个FIN给客户端
客户端发回 ACK 报文确认,并将确认序号设置为收到序号加1
图源:稀土掘金
问题:为什么不能把服务端发送的 ACK 和 FIN 合并起来,变成三次挥手?
因为服务端收到客户端断开连接的请求时,可能还有一些数据没有发完,这时先回复 ACK,表示接收到了断开连接的请求。等到数据发完之后再发 FIN,断开服务端到客户端的数据传送。