dns 找到了地址,spf 确定了路径,如何运输数据呢?今天讲 tcp。
计算机网络领域的特定技术是最后当你干这个事时才要用的,我对孩子们这样说,实际上你可以随便看一个快递单子来理解端到端传输协议。
源地址,目标地址一定要有,一个地址可能有不同住户,也就是 port 指示的,一系列相关联包裹的顺序编号也是必须,总共多少件,这是第几件等等,此外,一个包裹能不能被拆分运输,也要被标识,三吨大米可以拆分运输,而三吨大象就不行,能收多少,这个也要告知对方。哪些是 tcp,哪些是 ip,我是不区分的,因为本来它们就没有区分。
和快递包裹类似,tcp 不管具体运输路径,所以它是端到端的。
和快递包裹不同的是,tcp 指示一个双向的交互运输,如何在 “运输单” 上紧凑地控制这个双向运输过程是 tcp 协议的设计目标之一,序号 和 接收能力 标识本端信息,而 “ack” 则捎带对方的需求,但如果没有本端报文需要递送,ack 也能单独发送,这些信息在双向交互初始化时通过四次握手协商清楚,由于 ack 可稍带,四次握手合并为三次。
双向交互协议最自然的方式是 “单字节停等”,若果然如此,tcp 就是个再简单不过的协议,但为了效率,单字节停等扩展为单报文停等,报文子节流可拆分,最终是窗口停等,窗口内报文可丢可乱序,一次发送一窗数据就不得不有效处理丢包乱序问题。优化总是引入复杂。
如何检测丢包,一开始只有超时,后来有了更 trick 的方式,即快速重传。对于孩子而言,解释为什么三次重复 ack 标识丢包很轻松,他们可以自然理解为什么是三次,如果要解释,就是事不过三。没必要进一步引申 reordering,因为这不是重点。
tcp 影响了所有传输协议。
如果一开始的 tcp 不是现在这个 tcp,现在的互联网就会是另一番景象。
从 tcp 滑动窗口停等 中可以看到一些历史,另一些历史可以从编码和交互的视角来理解。
1970 年代典型的文件传输和远程登录(包括文件传输的 ftp 以及 email 交互命令)两类应用确实影响了 tcp 必须是流式停等协议。
首先,文件传输的对端需要精确拷贝,其次,远程登录实际上是自己跟自己交互,这就很有趣,传输的对端不是人,无法脑补纠错,而交互的本端却是自己。自己与自己交互不存在脑补的空间,比如输入一个 “s”,显然希望马上回显一个 “s”,“anderson” 是我自己输入的,回显 “andersoX” 时我会怀疑自己输入错了,而不是字母传丢了。
假想另一种平行历史,如果 1970 年代的核心应用是用一个传输协议向远端放电影,流式停等就再无必要,nack 可能会被用来提示关键数据丢失,也会有一个偶尔的指令反馈,但大部分时间,receiver 可能根本不会有任何反馈。拥塞控制大概会倾向于 receiver 的主动行为。
接下来可以想象,不会有如今样式的慢启动,也不会有内置的 reno aimd 策略,因为稀疏的反馈不足以驱动这些机制运行。如果 ack 不是 tcp 的必须字段,有关拥塞控制的所有机制都将改变,并且也不会出现 ack 过多导致的资源抢占问题,特别是在 wifi 环境下。
说说 aimd,这实际上是一个并不需要干预的自然过程,也印证了主动干预的合理性。
大片牧场承载着小规模羊群,但羊群规模会逐渐变大,当羊群规模略微超过牧场承载能力,羊群就会出现内卷性竞争,比如降低代谢率,接下来就会出现大规模争夺资源的缠斗,二者相斗必有一伤,在统计学意义上,羊群规模会快速减半,这就是 aimd。同理,当城市人口缓慢增加到人与人之间距离小于临界值,传染病就会肆虐从而快速减少人口,所以城市化进程达到一定程度必须停止。在理论上,统计复用资源不可能实现 100% 的利用率,这是需要用直感而不是数学讲明白的。
但不管怎样,tcp 依然重要。
浙江温州皮鞋湿,下雨进水不会胖。