一个问题:怎么可靠地建立连接
你想给朋友寄一封信。先打个电话确认"我现在寄可以吗",朋友说"可以",你说"好"。三句话完成确认,对方知道你真的要寄,你知道对方准备好了,可以开始寄了。
这通电话的逻辑,就是 TCP 三次握手的本质。问题是:为什么是三次不是两次或四次?
我们一步步推演。
两次握手为什么不够
假设两次握手就够:
- 客户端发 SYN("我要连你")
- 服务器回 SYN+ACK("好的,同意")
你想给朋友寄一封信。先打个电话确认"我现在寄可以吗",朋友说"可以",你说"好"。三句话完成确认,对方知道你真的要寄,你知道对方准备好了,可以开始寄了。
这通电话的逻辑,就是 TCP 三次握手的本质。问题是:为什么是三次不是两次或四次?
我们一步步推演。
假设两次握手就够:
你在一段公路上开车。前方堵了 10 公里,所有车都慢下来,挤在一起。最后一公里完全不动。这就是网络拥塞——路由器队列满了,新到的包被丢,丢包又触发重传,重传又让队列更满,雪崩。
1986 年互联网经历了一次"拥塞崩溃"——LBL 到 UC Berkeley 的链路 400 米距离,理论 32Kbps 带宽,因为 TCP 不断重传拥塞丢失的包,实际吞吐量降到 40bps,1/800。Van Jacobson 1988 年发表那篇经典论文《Congestion Avoidance and Control》,发明了 TCP 拥塞控制四大算法,从此互联网没再大规模崩溃过。
假设你给朋友寄礼物,每秒寄一个。朋友家里只能放 10 个礼物,他每秒最多拆 1 个。你寄到第 11 秒,他家满了,他只能把第 11 个礼物扔到门外——礼物丢了。怎么办?
他应该告诉你"我满了,别寄了"。等他家有空位了,他再告诉你"可以寄了"。这种"接收方按自己节奏告诉发送方"就叫流量控制。
TCP 的流量控制就是这个机制。接收方通过 TCP 头部的"窗口"字段告诉发送方"我现在能收多少"。发送方按这个窗口大小发数据,绝不超额。
你家电脑有 5 个应用同时在跑——Chrome、Safari、Spotify、微信、邮件。包从远端服务器到你的电脑,IP 层已经把包送到了正确机器。但这个包是给哪个应用的?
这就是运输层要解决的问题。运输层在 IP 层(网络层)之上,给每个应用分配一个端口号作为标识。包到主机后,TCP/UDP 头里的端口号告诉主机"这个包给 Chrome,不是给微信"。
端口号是运输层给"应用"的逻辑地址。0-1023 是知名端口(HTTP=80, HTTPS=443, SSH=22, DNS=53),1024-65535 是临时端口(客户端用)。