本文尝试用动画来讲解这个知识点,希望读者能更轻松地理解TCP交互的本质。TCP三次握手TCP三次握手就像两个人在街上相隔50米看到对方,但是因为雾霾等原因不能100%确定,所以要互相挥手来确定是否他们彼此认识。由于动画太大,请点此观看动画。张三先是向李四挥了挥手。看到张三向自己招手后,李斯冲对方点了点头,挤出一个笑容(ack)。看到李斯笑了之后,张三确认李斯身份成功(进入确定状态)。但李斯还是有些疑惑,四下打量。难不成张三看的是别人?他还需要确认。于是李四也向张三招了招手。张三看到李斯向自己招手,就知道对方是在寻求自己的确认。于是他也点了点头,挤出一丝笑容(ack)。看到对方的笑容后,李斯确定张三是在跟自己打招呼(进入既定状态)。于是两人加快了脚步,走到了一起,紧紧相拥。由于动画太大,请点此观看动画。我们可以看到这个过程有四个动作:张三招手李四点头微笑李四招手张三点头微笑李四连续进行了2个动作,先是点头微笑(回复对方),然后是挥手再次(求证实),其实这两个动作是可以结合的,点头和微笑(syn+ack)同时挥手。于是四个动作简化为三个动作,张三招手→李四点头微笑招手→张三点头微笑。这就是三次握手的本质。中间动作是两个动作的组合。我们看到有两个中间状态,syn_sent和syn_rcvd,这两个状态叫做“半开”状态,意思是向对方挥手,但是还没有来得及看到对方的点头和微笑。syn_sent是主动opener的“半开”状态,syn_rcvd是被动opener的“半开”状态。客户端是主动开启者,服务器是被动开启者。syn_sent:syncpackagehasbeensentsyn_rcvd:synpackagehasbeenreceivedTCP数据传输TCP数据传输是两个人在空中的对话,有一点距离,所以对方需要反复确认听到了自己的话。由于动画太大,请点此观看动画。张三喊了一个字(data),李四听到后,想回复张三听到了(ack)。要是张三喊了些什么,半天都没有听到李斯的回答,张三还以为自己的话被大风吹走了,李斯没有听到,需要再喊一声。这就是TCP重传。也有可能李斯听到了张三的话,但是李斯给张三的回复被大风吹走了,以至于张三没有听到李斯的回复。张三分不清是自己的话被大风吹走了,还是李四的回答被大风吹走了。张三也没在意,直接转发了过去。既然会重传,同一句话李斯可能听过两次,就是“去重”。“重传”和“去重”工作已经由操作系统的网络内核模块帮我们处理好了,用户层不需要关心。张三可以打电话给李四,李四也可以打电话给张三,因为TCP连接是“双工”的,双方都可以主动发起数据传输。但是不管是哪一方喊话,都需要得到对方的确认才能认为对方收到了自己的喊话。张三可能是个高射炮,一口气说了八句。这时候李斯不能一句一句的回复,而是一连听完这八句话,一起回复对方,说你之前说的八句话我都听到了,这是批量ACK。但是张三一次也不能说太多,李斯的大脑短时间内也未必能消化太多。两者之间需要协商适当的发送和接收速率。这是“TCP窗口大小”。网络环境中的数据交互比人与人之间的对话更为复杂,存在数据包乱序的现象。从同一个源发出的不同数据包在“互联网路由”上可能会经过不同的路径,最终到达同一个地方时,顺序是不同的。操作系统的网络内核模块负责对数据包进行排序,到达用户层时顺序完全一致。TCP挥手四次,TCP断开连接的过程与建立连接的过程类似,只是中间的两步并不总是合为一步。所以分为以下四个动作:张三挥手(fin)李四伤心一笑(ack)李四挥手(fin)张三难过一笑(ack)由于动画太大,请点这里查看动画中间的两个动作之所以没有合并,是因为TCP有一个“半关闭”状态,即单向关闭。张三已经摆了摆手,人还没有走,他只是不说话,耳朵却还能听得见,李斯还在继续喊。等李斯累了之后,便不再多说,对着张三摆了摆手。张三黯然一笑,彻底完蛋了。由于动画太大,请点此观看动画。上面有一个很特殊的状态time_wait,是主动关机的一方回复对方一波后进入的一个长期状态。该状态标准持续时间为4分钟,4分钟后进入Closed状态释放socket资源。不过这个时间在具体实现中是可以调整的。就像是主动提出分手的一方的责任。是你提出分手,你要付出代价。这个后果就是持续4分钟的time_wait状态,socket资源(端口)无法释放,就像寡妇期一样,期间socket资源(端口)无法回收。它的作用是重传上次的ack报文,保证对方能收到。因为如果对方没有收到ack,就会重传fin报文,time_wait状态的socket会立马重发ack报文给对方。同时,在这段时间里,对话过程中Internet路由上的链路产生的残留包(因为路径太崎岖,数据包走的时间太长,重传的包已经收到,而原来的数据包尚道)传过去,会被立即丢弃。4分钟足以让这些残留信息彻底消失。否则,当重新使用新端口时,这些残留数据包可能会干扰新链路。4分钟为2MSL,每个MSL为2分钟。MSL是MaximumSegmentLifetime——最长的消息生命周期。这个时间是由官方的RFC协议规定的。至于为什么是2个MSL而不是1个,我还没看到很满意的解释。四波并不总是四波,中间的两个动作有时可以组合在一起。这时候变成挥手三下,主动关闭方会直接从fin_wait_1状态进入time_wait状态,跳过fin_wait_2状态。总结TCP状态转换是一个非常复杂的过程。本文仅对一些简单的基础知识点进行类比讲解。更多关于TCP的知识还是需要读者去搜索相关的技术文章来深入学习。如果读者对TCP的基础知识有扎实的掌握,那么理解高级知识也不会太困难。钱文品(老钱),十年互联网分布式高并发技术老手,目前是掌阅服务器技术专家。精通Java、Python、Golang等计算机语言,开发过游戏,做过网站,编写过消息推送系统和MySQL中间件,实现过开源ORM框架、Web框架、RPC框架等。经营个人公众号码洞(ID:代码孔)。
