期末月叠加面试真是嘎嘎上压力,周二快手一面,呜呜呜,我要当手孝子。

我们一般说网络有七层,是指OSI模型,从下到上依次为:

  1. 物理层 (Physical Layer)
  2. 数据链路层 (Data Link Layer)
  3. 网络层 (Network Layer)
  4. 传输层 (Transport Layer)
  5. 会话层 (Session Layer)
  6. 表示层 (Presentation Layer)
  7. 应用层 (Application Layer)

而实际上我们采用的都是TCP/IP模型,只有四层(有时也说五层)

从下到上依次为:

  1. 网络接口层,也叫链路层
  2. 网络层
  3. 传输层
  4. 应用层

五层模型将网络接口层拆开,分为物理层、数据链路层

而TCP和UDP都是两种常见的传输层协议

TCP:面向连接的,可靠的,基于字节流的传输层通信协议

  • tcp是一种面向连接的协议,在通信之前要在发送方和接收方之间建立连接,然后通信结束后关闭连接。建立和关闭的过程被称为三次握手和四次挥手,确保数据的可靠传输。
  • 可靠性:它使用序列号和确认机制来确保数据包的有序性和完整性,如果数据包丢失或者损坏,tcp会重新发送丢失的数据包,直到接收方正确接收为止。
  • 流量控制和拥塞控制:TCP采用流量控制和拥塞控制算法,确保数据发送的速率不会超过接收方的接收能力,并防止网络拥塞
  • 有序传输:TCP确保数据包按照发送的顺序到达,并在接收方重新组装成正确的顺序
  • 适用于可靠传输的场景:文件传输,电子邮件,网页浏览

UDP:无连接的,不可靠的,基于数据报的传输层通信协议

  • UDP是一种无连接的协议,与tcp不同,UDP在通信之前不需要建立连接,直接发送数据包,使得UDP比TCP更加轻量级
  • 不可靠性:UDP不提供可靠的数据传输。它发送数据包之后不会关心数据包是否会到达接收方,因此,如果数据包丢失或者损坏,UDP不会重新发送,也不会提供确认机制
  • 速度较快:没有连接建立和确认过程,UDP传输速度较快,适用于实时传输,如实时音频,和视频流
  • 无序传输:UDP不保证数据包的有序性,因此接收方接收到的数据包是无序的
  • 适用于实时传输的场景:UDP适用于对数据传输可靠性不高的场景,如实时游戏、流媒体等,其中实时性比准确性更重要

两者的区别

  1. 连接性

    • TCP:面向连接,通信前需建立三次握手,确保可靠连接。
    • UDP:无连接,直接发送数据,无需建立连接。
  2. 可靠性

    • TCP:提供可靠传输,通过序列号、确认机制、重传机制和流量控制确保数据无丢失、无差错、按序到达。
    • UDP:不可靠,无确认机制,数据可能丢失、乱序或重复。
  3. 传输效率

    • TCP:因有连接建立、确认和重传等机制,效率较低,延迟较高。
    • UDP:无额外开销,效率高,延迟低,适合实时传输。
  4. 数据传输方式

    • TCP:基于字节流,无消息边界,数据按流传输。
    • UDP:基于数据报,保留消息边界,每个数据报独立。
  5. 适用场景

    • TCP:适合需要高可靠性的场景,如 HTTP、FTP、SMTP(网页浏览、文件传输、邮件)。
    • UDP:适合实时性要求高、允许少量丢包的场景,如视频流、语音通话(VoIP)、DNS 查询、游戏。
  6. 服务形式

    • TCP提供一对一的全双工通信,确保数据按序、无差错、无丢失地传输。
    • UDP支持一对一、一对多(多播)、多对多通信,适合广播或多播场景。
  7. 分片方式

    TCP

    • 数据以字节流形式传输,无明确的消息边界。
    • 分片由 TCP 协议栈自动处理,将数据分割为适合的段(Segment),每个段包含序列号以确保按序重组。
    • 分片大小根据最大段大小(MSS, Maximum Segment Size)动态调整,通常由网络 MTU(最大传输单元)决定。
    • 接收端会根据序列号重组数据流,处理乱序或丢失的段。

    UDP

    • 数据以数据报形式传输,每个数据报独立,保留消息边界。
    • 分片由应用层或网络层(IP层)处理,UDP 本身不对数据报分片。
    • 如果 UDP 数据报大小超过 MTU,IP 层会进行分片,接收端由 IP 层重组。
    • UDP 不负责乱序或丢失的数据报重组,应用层需自行处理。

TCP的重传机制是如何实现的

在TCP通信中,每个发送的字节都有唯一的序号,而每一个接收的字节都有一个ack确认号。发送方维护了一个发送窗口,接收方维护了一个接收窗口,发送方发送完数据后等待接收方的确认。

数据发送失败后有两个重传机制,一个是超时重传,一个是快重传。

超时重传

发送方为每一个发送的数据设置一个定时器,这个定时器的时长称为超时时间(RTO,是根据往返时间RTT确定的)。发送方假设在这个RTO时间内,数据能够到达接收方并得到确认,如果在超时时间内没有收到确认ack信号,发送方就认为数据丢包或者损坏,触发超时重传。超时后,发送方重传未确认的最早数据段,并调整拥塞窗口(通常降为1 MSS,进入慢启动)。

缺点

  • RTO较长,延迟高。
  • 进入慢启动

适用于连续丢包或者网络严重拥塞

快重传

  • 接收方收到乱序数据段(Out-of-Order),重复发送最近确认的ACK(即期望的下一个字节序号)。

  • 发送方收到3个相同ACK,推测该ACK后的数据段丢失,立即重传。

  • 快重传常与快恢复(Fast Recovery)结合:

    • 拥塞窗口减半(cwnd=cwnd/2+3⋅MSS),进入快速恢复而非慢启动。
  • 优点:

    • 比慢重传快,减少不必要的等待。
    • 结合快速恢复,拥塞控制更平滑。
  • 缺点:

    • 需足够重复ACK(至少3个),对大量丢包或尾部丢包效果差。
    • 可能误判(重复ACK可能由重排序引起)。

流量控制

流量控制的核心机制:滑动窗口

  • 定义:TCP使用滑动窗口协议(Sliding Window Protocol)实现流量控制。接收方通过通告窗口大小(Advertised Window,简称rwnd)限制发送方的发送速率。
  • 原理:
    • 接收方在TCP报头中携带窗口大小字段(16位,单位字节),告知发送方其接收缓冲区剩余容量。
    • 发送方根据接收方的窗口大小(rwnd)和拥塞窗口(cwnd)选择实际发送窗口:Effective Window=min⁡(rwnd,cwnd)Effective Window=min(rwnd,cwnd)
    • 发送方只能发送未确认数据和窗口允许的数据量,确保不超过接收方处理能力。
  • 滑动窗口运作:
    • 窗口随ACK左移,释放已确认数据的空间。
    • 接收方处理数据后,窗口右移,通告新的rwnd。

2. 实现步骤

  1. 接收方通告窗口
    • 接收方在每次ACK中携带rwnd,反映其缓冲区可用空间。
    • 初始rwnd由接收方缓冲区大小决定(典型为几KB到几十KB)。
  2. 发送方调整发送速率:
    • 发送方根据rwnd动态调整未确认数据量(in-flight data)。
    • 若rwnd=0,发送方暂停发送,但可发送1字节探测包(Zero Window Probe)检查窗口是否恢复。
  3. 窗口更新:
    • 接收方处理缓冲区数据后,发送新的ACK,更新rwnd。
    • 若rwnd增大,发送方恢复或增加发送。

3. 关键特性

  • 动态调整:
    • rwnd随接收方缓冲区状态实时变化,适应应用层处理速度。
  • 防止缓冲区溢出:
    • 确保发送数据量不超过接收方缓冲区容量。
  • 零窗口处理:
    • 当rwnd=0,发送方等待窗口更新,定时发送探测包避免死锁。
  • 与拥塞控制协同:
    • 流量控制(基于rwnd)与拥塞控制(基于cwnd)结合,发送窗口取两者最小值。

TCP的拥塞控制

首先是慢启动阶段,初始阶段TCP会以较小的发送窗口开始传输数据,一般是2个或者3个四个MSS,随着每次成功收到ack信号,发送窗口每次变为上次的两倍,指数型增长,直到大于临界窗口之后,变为拥塞避免阶段,线性增长,每次增加一个MSS。

初始的临界窗口一般根据上次的拥塞点确定或者一个较大的值(16MSS)

超时重传之后,重新进入慢启动,这时临界窗口的大小是发生拥塞时未被确认的数据量的二分之一(近似为cwnd的一半),但不能小于2个MSS

而快重传,临界窗口也被设置为发生拥塞时未被确认的数据量的二分之一(近似为cwnd的一半),然后拥塞窗口设置为临界窗口加三个MSS。

什么是TCP粘包?

粘包是指在TCP传输中,多个应用层数据包在接收端被合并为一个数据块,导致无法直接区分原始数据包边界。TCP是面向流的协议,不保证数据包的独立性,发送端可能将多个小数据包合并,接收端可能将数据分段或合并处理。

粘包原因

  1. 发送端优化

    • TCP的Nagle算法将小数据包合并,减少网络开销。
    • 发送缓冲区可能一次性发送多个应用层数据。
  2. 接收端处理

    • 接收缓冲区可能将多个数据包合并为一个读操作。
    • 接收数据不按发送时的包边界分割。
  3. 网络传输

    • 数据在网络中可能因时序或分段重组,导致粘包或分包。

粘包示例

  • 发送端连续发送 “Hello” 和 “World”,接收端可能为 “HelloWorld”。
  • 发送端发送 “Msg1|Msg2”,接收端可能将 “|Msg2” 分到下一次读操作。

如何解决粘包?

解决粘包需要在应用层定义协议,确保接收端能正确解析数据包边界。以下是几种常见方法:

1. 固定长度头部

  • 方法:
    • 每个数据包前加固定长度的头部(如4字节),表示数据包长度。
    • 接收端先读取头部,解析长度,再读取指定长度的数据。
  • 优点:简单,易实现。
  • 缺点:头部长度限制最大数据包大小(如4字节限制4GB)。
  • 示例:
    • 发送格式:[4字节长度][数据]
    • 接收伪代码:length=read(4 bytes)data==read(length bytes)length=read(4 bytes)data==read(length bytes)

2. 分隔符

  • 方法:
    • 在数据包间插入特定分隔符(如 “\n” 或 “|”)。
    • 接收端按分隔符分割数据。
  • 优点:灵活,适合文本数据。
  • 缺点:需确保数据内不含分隔符,或进行转义处理。
  • 示例:
    • 发送:”Hello\nWorld\n”
    • 接收端按 “\n” 拆分。

3. 固定长度数据包

  • 方法:
    • 每个数据包固定长度,不足补填充(如空格或0)。
    • 接收端按固定长度读取。
  • 优点:实现简单,边界清晰。
  • 缺点:浪费带宽,适合长度一致的场景。
  • 示例:
    • 每个包固定100字节,”Hello” 补95字节填充。

4. 消息格式化(如TLV或JSON)

  • 方法:
    • 使用结构化格式(如Tag-Length-Value或JSON)定义消息。
    • 接收端按格式解析。
  • 优点:支持复杂数据,扩展性强。
  • 缺点:解析复杂度较高。
  • 示例:
    • JSON格式:{"len":5,"data":"Hello"}

5. 应用层超时机制

  • 方法:
    • 在接收端设置超时,若一段时间未收到完整包,视为粘包或分包,触发重试或错误处理。
  • 优点:辅助解决分包问题。
  • 缺点:需调优超时时间,避免误判。