面试题

作者:

在

一、三次握手的具体过程

TCP 是面向连接的可靠传输协议,通信前需通过“三次握手”建立连接。以客户端主动连接服务器为例:

image-20260608123555082

二、为什么需要第三次握手?—— 核心原因

第三次握手是为了防止已过期的连接请求报文突然又传到服务器,导致服务器错误地建立一个无效连接,从而浪费资源。

image-20260608123828237


粘包问题

==原因==:

发送方、接收方 和 两个维度分解。

1. 发送方原因:TCP 协议栈的优化行为

  • Nagle算法(默认开启): 为了减少小包数量,TCP 会等待一小段时间(通常 200ms),如果发送缓冲区中有多个小消息,或者等待期间收到了之前消息的 ACK,就会将多个小消息合并成一个 TCP 段发出。 → 导致:多个应用层消息粘在一起(粘包)。
  • 最大分段大小(MSS)限制: TCP 段的数据部分不能超过 MSS(通常由路径MTU 决定,典型值 1460 字节)。如果一个应用层消息大于 MSS,TCP 会将其拆分成多个段。 → 导致:一个消息被分成多次发送(拆包)。
  • 发送缓冲区策略: 应用程序 write 的数据先复制到内核发送缓冲区。TCP 会按照自身的拥塞控制和流量控制来决定何时真正发送、发送多少。即使你分两次 write,也可能被一次性发出。

2. 接收方原因:应用程序读取不及时

  • 接收缓冲区堆积: 内核将收到的 TCP 段存入接收缓冲区。如果应用程序调用 recv 不够快,多个消息就会堆积在缓冲区中。当应用程序最终调用 recv 读取一个大块时,可能一下子取走多个消息。 → 导致:粘包。
  • 用户缓冲区长度限制: 调用 recv(buf, len) 时,若 len 小于消息的实际长度,则只能读出部分数据,剩余数据留在缓冲区中。下次再读时,可能读到某个消息的后半部分,或者读到下一个消息的前半部分。 → 导致:拆包(也叫半包)。

==本质==

TCP 是面向字节流的协议,它只保证字节序列的有序、可靠传输,但不维护、不识别应用层消息之间的边界。 因此,多个应用层消息在字节流中可能“粘”在一起,也可能一个消息被拆成多个片段,“粘包”和“拆包”是同一本质的两种表现形式。

解决方案

一.直接使用已封装好消息边界的库/协议

不直接操作裸 Socket,而是==选用已经内置了粘包处理能力==的:

image-20260608100253598

二、为什么使用(原因)

  • TCP 粘包是必然且无法避免的 只要使用裸 TCP Socket,就必须手动处理粘包/拆包,否则程序必然出错。

  • 手动处理粘包具有较高复杂度 需要考虑:缓冲区管理、长度字段解析、跨包拼接、大消息分块、性能优化、错误恢复、恶意报文防护等。这些细节很容易写出 bug。

  • 成熟的库/协议已经解决了所有边界情况 经过全球海量生产环境验证,覆盖了各种网络异常、性能场景,不需要重复造轮子。

  • 团队协作与可维护性 统一使用标准协议(如 HTTP/gRPC),任何语言的客户端都能互通,且代码可读性高;而私有协议需要文档、对齐、调试,维护成本高。

三.优点(使用带来的好处)

image-20260608100431720

==总结==:使用现成库/协议解决粘包,就是用“行业标准方案”替代“手写轮子”,换来高效率、高可靠、低维护成本的工程收益。在实际项目中,除非有极轻量的私有协议需求,否则这永远是首选做法。


TCP四次挥手过程,分别有哪些定时器,都是干什么的

image-20260608125132405

image-20260608125238244


TCP四次挥手什么情况会出现time_wait,怎么排查是什么问题

image-20260608131749620

image-20260608131935319

如何排查

排查 TIME_WAIT 问题,关键在于要区分 “这是否已经造成了实际故障” 。少量 TIME_WAIT 是 TCP 协议的正常行为,只有当数量过多导致资源耗尽时,才需要介入。

我把整个排查思路整理成了一个流程,你可以参考:

image-20260608132707724

具体内容详细问deepseek