计网知识收集

计网知识收集
mengnankkzhou基础知识
1.TCP 三次握手的过程
第一次握手(SYN):
- 动作: 客户端随机生成一个初始序列号
seq = x,设置 SYN 标志位为 1,发送给服务器。 - 状态转移: 客户端进入
SYN_SENT(同步已发送)状态。
第二次握手(SYN + ACK):
- 动作: 服务器收到 SYN 包后,也随机生成自己的初始序列号
seq = y,同时确认客户端的序列号ack = x + 1,设置 SYN 和 ACK 标志位均为 1,发送给客户端。 - 状态转移: 服务器从
LISTEN进入SYN_RCVD(同步收到)状态。
第三次握手(ACK):
- 动作: 客户端收到服务器的 SYN+ACK 包,为了确认自己收到了服务器的序列号,发送一个
ack = y + 1,序列号seq = x + 1,ACK 标志位为 1 的确认包给服务器。(此时,这个包已经可以携带应用层数据了)。 - 状态转移: 客户端进入
ESTABLISHED(已建立连接)状态。服务器收到此 ACK 后,也进入ESTABLISHED状态。
为什么需要三次握手?
- 防止历史(失效)连接初始化造成混乱(最主要原因): 网络是可能拥塞和延迟的。假设客户端发送了 SYN1(因网络卡顿未到达),于是超时重发了 SYN2。此时网络恢复,旧的 SYN1 先到达服务器。
- 如果是两次握手:服务器收到 SYN1 直接进入 ESTABLISHED 状态并开始发数据,这就建立了一个历史的“脏连接”,浪费了服务器资源。
- 如果是三次握手:服务器收到 SYN1 返回 SYN+ACK,客户端收到后,检查发现期望的应答不是这个(因为它当前期望的是 SYN2 的应答),客户端就会发送
RST报文强行中断这个历史连接。三次握手把决定权交给了客户端,让客户端来确认这个连接是不是它真正想要的。
- 可靠地同步双方的初始序列号(ISN): TCP 要保证数据不丢不重,必须靠序列号。双方都要告诉对方自己的 ISN。
- 客户端发 ISN,服务器确认(1、2次握手完成)。
- 服务器发 ISN,客户端确认(2、3次握手完成)。 最少需要这三次通信,才能保证双方的序列号都被对方可靠地接收并确认。
第三次握手(ACK)失败会发生什么?
这在面试中是极其考验实战经验的问题。
如果客户端发送了第三次 ACK,但网络丢包了,服务器没收到:
- 客户端视角: 客户端发完 ACK 后就认为连接成功了,状态已经是
ESTABLISHED。如果它开始发送数据包,服务器收到后会回复RST报文让其重置连接。 - 服务器视角: 服务器此时处于
SYN_RCVD状态。因为它没收到 ACK,它会认为自己的 SYN+ACK 丢了。于是它会触发超时重传机制,重新发送 SYN+ACK。- 通常会重传 5 次,并且每次等待时间呈指数级增长(如 1s, 2s, 4s, 8s, 16s)。
- 如果在最大重传次数后依然等不到客户端的 ACK,服务器就会将这个半连接从**半连接队列(SYN Queue)**中删除,释放资源。
2.TCP 挥手为什么需要四次?
这里的核心关键字是:全双工通信(Full-Duplex) 和 半关闭状态(Half-Close)。
TCP 连接是双向的(就像一条双向车道),数据的发送和接收是相互独立的。这就意味着,关闭连接也必须分两个方向独立进行。
- 第一次挥手(FIN): 客户端数据发完了,告诉服务器:“我没有数据要发了”(发送 FIN)。注意:此时客户端只是不能发数据了,但依然可以收数据。
- 第二次挥手(ACK): 服务器收到 FIN,马上回复一个 ACK:“我知道你发完了”。此时客户端到服务器的方向关闭,连接处于半关闭状态。
- 为什么这里有停顿? 因为服务器收到 FIN 的时候,它的应用层可能还有数据没处理完,或者还有数据没发送完! 所以服务器还要继续把剩下的数据发给客户端。客户端也要继续接收。
- 第三次挥手(FIN): 等服务器的数据也终于全部发完了,它也会发一个 FIN 告诉客户端:“我也没数据要发了,可以正式分手了”。
- 第四次挥手(ACK): 客户端收到服务器的 FIN,回复一个 ACK:“好的,再见”。
简单来说:建立连接时,服务器的 SYN 和 ACK 可以合并成一个包发送(第二次握手)。但断开连接时,由于被动方往往还有残余数据要发送,所以它的 ACK(第二次挥手)和 FIN(第三次挥手)必须分开发送,这就导致了必须是四次挥手。
3.描述一下https中的SSL/TLS
在深入细节前,我们要明确 SSL/TLS 解决了 HTTPS 的三个核心问题:
- 机密性 (Confidentiality):通过对称加密防止信息被窃听。
- 完整性 (Integrity):通过**MAC(消息验证码)**防止数据被篡改。
- 身份认证 (Authentication):通过数字证书确保你访问的确实是目标服务器。
这是最体现底层设计精妙的地方。TLS 握手的本质是:在不安全的信道上,安全地协商出一个只有双方知道的对称密钥。
阶段一:密码套件协商 (Client Hello & Server Hello)
- Client Hello: 客户端发送它支持的 TLS 版本、密码套件列表(如
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256)以及一个客户端随机数 (Client Random)。 - Server Hello: 服务端选定版本、密码套件,并给出服务端随机数 (Server Random)。
阶段二:身份验证与密钥交换
这是区分资深开发者的关键点,通常涉及 ECDHE 算法:
- Certificate: 服务端发送证书链。客户端会根据本地根证书校验签名,确保服务器公钥的真实性。
- Server Key Exchange: 如果使用 ECDHE,服务端会生成一个椭圆曲线点(临时公钥)并用私钥签名发送给客户端。
- Client Key Exchange: 客户端验证签名后,也生成一个自己的临时公钥发送给服务端。
阶段三:生成会话密钥
此时,双方都拥有:Client Random、Server Random 以及通过 ECDHE 算法算出的 Pre-Master Secret。
- 双方利用这三个参数,通过 PRF (伪随机函数) 计算出最终的 Master Secret (主密钥)。
- 主密钥再派生出对称加密密钥、MAC 密钥等。
深度思考:为什么要用三个随机数?因为 SSL 不信任客户端或服务端伪随机数的独立性,三个随机数混合可以极大增加密钥的随机性,确保安全性。
握手完成后,所有应用数据(如 HTTP Body)都通过记录协议处理。
- 分片 (Fragmentation):将高层协议的数据切分成适当大小。
- 压缩 (Compression):可选,但现代 TLS 为了防范攻击(如 CRIME)通常禁用。
- 添加 MAC (Message Authentication Code):通过哈希算法(如 SHA-256)保证数据完整性。
- 加密 (Encryption):使用协商好的对称密钥(如 AES-GCM)进行加密。
传统的 RSA 密钥交换模式下,如果服务器私钥泄露,过去录制的所有加密流量都可以被解密。 而 ECDHE (Elliptic Curve Diffie-Hellman Ephemeral) 算法生成的临时密钥对是“瞬时”的。即使服务器私钥泄露,攻击者也无法推算出之前的 Pre-Master Secret。这就是前向安全性,也是为什么现代互联网强制要求使用 ECDHE 的原因。
4.描述一下TIME_WAIT状态,它出现在tcp链接的哪个位置
TIME_WAIT 仅出现在 主动关闭连接的一方(Active Closer)。
当一方完成数据传输,发送 FIN 包并经历完整的四次挥手流程后,它不会直接进入 CLOSED 状态,而是停留在 TIME_WAIT 状态。
四次挥手与状态流转
- 主动方发送
FIN,进入FIN_WAIT_1。 - 被动方回复
ACK,进入CLOSE_WAIT;主动方接收后进入FIN_WAIT_2。 - 被动方发送
FIN,进入LAST_ACK。 - 主动方接收
FIN并发送最后的ACK,此时主动方即刻进入TIME_WAIT状态。
TIME_WAIT 的持续时间通常是 2MSL(Maximum Segment Lifetime,报文最大生存时间的 2 倍,Linux 下通常为 60 秒)。设计这个“漫长”等待期的原因有二:
A. 保证最后的 ACK 能到达对端
如果主动方发送的最后一个 ACK 在网络中丢失,被动方(处于 LAST_ACK 状态)会触发超时重传 FIN。
- 如果主动方没有
TIME_WAIT而是直接关闭,当它再次收到这个重传的FIN时,会回复RST。 - 有了
TIME_WAIT,主动方可以重新发送ACK,确保被动方能够正常进入CLOSED状态。
B. 防止“旧报文”干扰新连接
网络路径复杂,某些报文可能会在路由器中“迷路”后又重新出现。
- 如果没有
TIME_WAIT,且立刻建立了一个相同 五元组(源IP、源端口、目的IP、目的端口、协议)的新连接。 - 旧连接的迟到报文可能被新连接接收,导致逻辑错误或数据损坏。
- 2MSL 确保了旧连接产生的所有报文都在网络中自然消失。
5… HTTP 请求头里面有些什么
- 核心路由与连接管理 (Routing & Connection)
这是 HTTP 请求能够成功到达目标服务器并维持通信的基础。
Host:(极其重要) 指定请求的目标域名和端口号。在单台服务器部署多个网站(虚拟主机)时,Nginx 就是依靠Host头来决定把请求路由给哪个后端服务的。Connection:控制网络连接的状态。在 HTTP/1.1 中默认是keep-alive(长连接),这意味着 TCP 连接在发送完响应后不会立即关闭,以便复用,从而降低握手开销。
- 内容协商 (Content Negotiation)
客户端通过这类请求头告诉服务端:“我能接收什么样的数据”。
Accept:客户端期望接收的数据格式。例如application/json或text/html。如果 Spring Boot 接口返回 XML,而客户端Accept只写了application/json,就会报 406 Not Acceptable 异常。Accept-Encoding:客户端支持的压缩算法,如gzip,deflate,br(Brotli)。服务端据此对响应体进行压缩,大幅节省带宽。Accept-Language:客户端期望的自然语言,常用于国际化 (i18n) 路由。
- 请求体描述 (Entity Information)
当请求带有 Body 时(如 POST/PUT),需要告诉服务端 Body 的特征。
Content-Type:请求体的 MIME 类型。最常见的是:application/json:现代 RESTful API 的标配。application/x-www-form-urlencoded:传统的表单提交。multipart/form-data:用于文件上传。
Content-Length:请求体的字节长度。如果服务端收到的数据少于这个值,会等待;如果多于这个值,会截断。
- 身份认证与状态维持 (Auth & State)
HTTP 协议本身是无状态的,依靠这些头来实现“记住你是谁”。
Authorization:携带认证凭证。在微服务和前后端分离架构中,最常见的是Bearer <JWT_TOKEN>。Cookie:携带服务端之前颁发并存储在客户端的 Cookie 键值对,传统的 Session 机制就是依靠传递JSESSIONID的 Cookie 来维持状态的。
- 缓存控制 (Cache Control) - 面试高频区
优秀的缓存设计能扛下极其夸张的并发,这些头是前端与服务端协商缓存的核心。
Cache-Control:控制缓存的策略(如no-cache,max-age=3600)。- 协商缓存双雄:
If-Modified-Since:配合服务端的Last-Modified使用,询问“在这个时间点之后,文件修改过吗?”。If-None-Match:配合服务端的ETag(文件内容的哈希值)使用,询问“这个文件的指纹变了吗?”。没变的话服务端直接返回 304 Not Modified。
- 来源追踪与安全防护 (Tracking & Security)
User-Agent(UA):发起请求的客户端信息(浏览器版本、操作系统等)。常用于基础的埋点统计、PC/移动端适配以及初级的反爬虫策略。Referer:记录当前请求是从哪个页面的链接跳过来的。我们常利用这个头在 Nginx 层做防盗链,或者在网关层做 CSRF(跨站请求伪造)防护。
- 分布式与微服务生态(资深必谈的“自定义头”)
在现代微服务架构中,请求往往要经过 CDN、WAF、API 网关等层层代理,原生头信息可能会丢失,因此我们极其依赖以下扩展头:
X-Forwarded-For/X-Real-IP:用于在经过多层反向代理后,透传客户端的真实物理 IP,否则你服务里取到的永远是网关的 IP。Trace-Id/Span-Id:在分布式链路追踪系统(如 SkyWalking、Zipkin)中,我们会在网关处生成一个全链路唯一的 ID 放入请求头,后续的所有微服务调用(哪怕是 Feign 或 RestTemplate)都会携带这个头,借此把整个请求日志串联起来。











