TCP相关

如何保证可靠传输

  • 三次握手建立连接

  • 序列号和确认号保证有序传输

    每个数据带有序号 seq,接收方返回 ack 告知发送方已接受到数据,可以继续发送

  • 重传机制

    • 超时重传,超时还未收到 akc 后,重传可能丢失的数据
    • 快速重传,当连续收到三个相同 ack 后,立即重传可能丢失的数据
  • 流量控制

    维护一个代表接收能力的滑动窗口,若接收缓冲区快满了,就缩小窗口,反之扩大窗口

  • 拥塞控制

    网络拥堵时,TCP 会减慢发送速度,防止因网络拥堵丢失大量数据

  • 四次挥手断开连接



三次握手

假设客户端为 A,服务器为 B

  • 第一次握手(SYN)
    • A 发送一个 SYN 包给 B,请求建立连接
    • 进入 SYN_SENT 状态
  • 第二次握手(SYN-ACK)
    • B 收到后,回复一个 SYN-ACK 包,表示同意连接,并请求建立反方向连接
    • B 进入 SYN_RCVD 状态
    • 此时为半连接队列
  • 第三次握手(ACK)
    • A 收到后,发送一个 ACK 包给 B,表示连接建立成功
    • A 进入 ESTABLISHED 状态,B 收到ACK后也进入 ESTABLISHED 状态
    • 此时为全连接队列

此时,连接正式建立,双方向都可以开始发送数据了

为什么不是两次?

两次只进行到 B 回复 SYN-ACK 包,A 只知道 B 收到了自己的请求,但不知道 B 是否准备好接受数据

为什么不是四次?

三次已经保证双方都能接收和发送数据,无需再做一次

也可以将 B 给 A 的包拆成 SYN 和 ACK 分开发送,但没必要



四次挥手

假设客户端为 A,服务器为 B

  • 第一次挥手(FIN)

    A 发送一个 FIN 报文,表示它已经没有数据要发送了,请求关闭连接

  • 第二次挥手(ACK)

    B 收到 FIN 报文后,发送一个 ACK 报文作为确认。此时 A 到 B 的数据通道关闭,但 B 还可以继续发数据给 A

  • 第三次挥手(FIN)

    B 完成自己的数据发送后,也发送一个 FIN 报文,请求关闭连接

  • 第四次挥手(ACK)

    A 收到 FIN 报文后,发送一个 ACK 报文确认。此时,整个连接关闭

  • 进入 TIME_WAIT

    强制等待 2MSL(两倍最大报文段生存时间),即一个来回的时间

    防止旧连接中还在路上的数据包被新连接接收

    确保最后一个 ACK 被对方收到,保证整个连接关闭

为什么不能三次?

TCP 是双向通信,双方都可以接收和发送数据,三次挥手只能关闭一个方向,导致一方的数据未发完

为什么不是五次?

四次已经能实现双向关闭,额外的操作会浪费资源

挥手过程双端分别经历哪些状态?

TIME_WAIT 过多

占用大量端口,影响并发性能

解决方案

  • 端口复用
  • 使用长连接



UDP

TCP 与 UDP 的区别

长连接和短连接




HTTP

为什么物联网设备用 MQTT 而非 HTTP?

  • 轻量级
    • 物联网设备一般性能低、带宽小、电池供电,MQTT 的开销小,消息格式简单,很适用
    • HTTP 需要传输完整的 HTTP 头,建立和关闭 TCP 连接,开销大
  • 实时性和长连接
    • MQTT 支持长连接,可以实时推送数据(比如传感器数据、设备状态)
    • HTTP 是短连接,响应一次就关闭连接,不适用于实时或高频数据流
  • 发布/订阅模型
    • MQTT 用 Pub/Sub 模型,一个传感器端数据可以同时推送给多个订阅者(如多个监控系统)
    • HTTP 是点对点的请求/响应,设备需要主动请求,不利于事件驱动的物联网场景
  • 不稳定网络适应性
    • MQTT 有 QoS(质量服务等级)机制,支持在不稳定网络中保持消息可靠送达
    • HTTP 在网络抖动、掉线场景下,恢复成本高、体验差

QoS 是怎么做的?

  • QoS 0 - 至多一次
    • 流程:发送方直接发送 PUBLISH 消息,不需要接收方 ACK 确认
    • 特点:快、消息可能丢失、适用于不重要/高频/实时数据,如温度曲线
  • QoS 1 - 至少一次
    • 流程:发送方发送带消息 ID(用于重传识别) 的 PUBLISH 消息,接收方收到后立即回复 PUBACK 确认,若发送方长时间没收到 PUBACK,会重发 PUBLISH 直至收到 PUBACK
    • 特点:确保至少送达一次、可能重复(手动去重)、适合重要但可容忍重复的场景,如告警通知
  • QoS 2 - 恰好一次
    • 流程:发送方发送带消息 IDPUBLISH,接收方收到后回复 PUBREC 表示已接收,发送方收到 PUBREC 后,发送 PUBREL 释放消息,接收方收到 PUBREL,处理消息,回复 PUBCOMP 完成
    • 特点:确保仅送达一次、无重复、网络开销大,流程复杂、适于需要严格保证幂等的数据传输,如金融交易、计费场景

幂等是什么?

同一个操作执行一次或多次,系统的最终结果是一样的

实现方法

  • 每个消息带唯一 ID,记录已处理过的消息,遇到重复的直接忽略
  • 插入数据库时加唯一索引,保证不重复插入
  • 数据库事务内判断是否已处理,未处理才执行操作



网络模型

OSI 七层模型

自上而下

  1. 应用层:HTTP、HTTPS
  2. 表示层:SSL/TLS
  3. 会话层:RPC
  4. 传输层:TCP、UDP
  5. 网络层:IP
  6. 数据链路层:以太网
  7. 物理层:光纤、网线


五层模型

自上而下

  1. 应用层:HTTP、HTTPS
  2. 传输层:TCP、UDP
  3. 网络层:IP
  4. 数据链路层:以太网
  5. 物理层:光纤、网线


TCP/IP 四层模型

自上而下

  1. 应用层:HTTP、HTTPS
  2. 传输层:TCP、UDP
  3. 网络层:IP
  4. 网络接口层:以太网、WIFI



网络 I/O 模型

I/O 多路复用

一个或少量线程/进程中同时监听多个 I/O 事件,提高系统效率,适用于高并发场景

Select

早期的I/O多路复用机制,使用固定长度的数组表示文件描述符集。每次调用select时都需要重新构建和检查文件描述符集

支持的文件描述符数量有限(通常为1024),在大规模连接的场景下效率较低


Poll

pollselect类似,但使用动态数组来存储文件描述符,因此没有select的最大连接数限制

每次调用时仍需遍历全部描述符,在处理大量连接时效率不高


Epoll

基于事件机制的 I/O 多路复用,当事件发生时,才会通知程序

LT 水平触发

只要时间处于活跃状态,就会一直通知程序,可能导致程序收到大量重复通知,增加开销

ET 边缘触发

仅在事件状态发生时通知程序,提高系统效率

ET 模式下如何保证数据全部读完?

ET 模式下,内核只通知一次,所以你必须循环读取直到读不到数据为止,即读取返回 EAGAINEWOULDBLOCK

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
while (true)
{
n = read(fd, buf, sizeof(buf));
if (n == -1)
{
if (errno == EAGAIN || errno == EWOULDBLOCK)
{
// 数据已全部读取完
break;
}
else
{
// 发生错误,处理错误
break;
}
}
else if (n == 0)
{
// 对方关闭连接
break;
}
// 处理读取到的数据
}




网络问题排查

客户端发送数据给服务器,服务器没反应

send() 返回成功后,数据一定发送出去了吗?

send() 返回成功只代表数据已成功复制到内核的发送缓冲区,不代表数据已经真正通过网络发送或对方已接收

  • 数据仍可能滞留在发送缓冲区
  • 如果网络出现拥堵或对方不可达,数据可能延迟或丢失
  • TCP 的可靠性体现在协议层的重传和确认机制,应用层仅能确认数据进入内核缓冲区



网络攻击

DDoS

攻击者通过大量肉鸡,向目标服务器发送海量请求,耗尽其带宽、CPU、内存,导致服务器瘫痪,无法为正常用户提供访问

常见攻击方式

  • 流量型:UDP 洪水,直接用流量压垮
  • 协议型:SYN 洪水、Ping of Death,利用协议漏洞让服务器耗尽资源
  • 应用层攻击:HTTP 请求洪水,高频率模拟正常用户操作

防护措施

  • CDN 或 WAF 缓解压力
  • 启用速率限制、IP黑名单
  • 及时识别异常流量模式