一、引言网络编程中TCP协议的三次握手和四次挥手的问题,在面试中是最为常见的知识点之一。不少读者都知道“三次”和“四次”,可是若是问深刻一点,他们每每都没法做出准确回答。 本篇文章尝试使用动画图片的方式,来对这个知识点进行“脑残式”讲解(哈哈),指望读者们能够更加简单、直观地理解TCP网络通讯交互的本质。 另外,社区里的另两篇文章《理论经典:TCP协议的3次握手与4次挥手过程详解》、《理论联系实际:Wireshark抓包分析TCP 3次握手、4次挥手过程》也是不错的入门文章,有兴趣可一并详读之。 友情提示:因本文gif动画较多,若是您的网速较慢,请耐心等候图片加载完成哦。 二、关于做者<ignore_js_op> ![]() 钱文品(老钱):毕业于华中科技大学计算机科学与技术专业,互联网分布式高并发技术十年老兵,目前任掌阅科技资深后端工程师。熟练使用 Java、Python、Golang 等多种计算机语言,开发过游戏,制做过网站,写过消息推送系统和MySQL 中间件,实现过开源的 ORM 框架、Web 框架、RPC 框架等。 做者的Github: https://github.com/pyloque 三、系列文章本文是系列文章中的第1篇,本系列大纲以下:
四、TCP 三次握手:“Say hello !”TCP 三次握手就比如两我的在街上隔着50米看见了对方,可是由于雾霾等缘由不能100%确认,因此要经过招手的方式相互肯定对方是否定识本身。 <ignore_js_op> ![]() 张三首先向李四招手(syn),李四看到张三向本身招手后,向对方点了点头挤出了一个微笑(ack)。张三看到李四微笑后确认了李四成功辨认出了本身(进入estalished状态)。 可是李四还有点狐疑,向四周看了一看,有没有可能张三是在看别人呢,他也须要确认一下。因此李四也向张三招了招手(syn),张三看到李四向本身招手后知道对方是在寻求本身的确认,因而也点了点头挤出了微笑(ack),李四看到对方的微笑后确认了张三就是在向本身打招呼(进入established状态)。 因而两人加快步伐,走到了一块儿,相互拥抱。 <ignore_js_op> ![]() 咱们看到这个过程当中一共是四个动做,张三招手--李四点头微笑--李四招手--张三点头微笑。其中李四连续进行了2个动做,先是点头微笑(回复对方),而后再次招手(寻求确认),实际上能够将这两个动做合一,招手的同时点头和微笑(syn+ack)。因而四个动做就简化成了三个动做,张三招手--李四点头微笑并招手--张三点头微笑。这就是三次握手的本质,中间的一次动做是两个动做的合并。 咱们看到有两个中间状态,syn_sent和syn_rcvd,这两个状态叫着「半打开」状态,就是向对方招手了,可是还没来得及看到对方的点头微笑。syn_sent是主动打开方的「半打开」状态,syn_rcvd是被动打开方的「半打开」状态。客户端是主动打开方,服务器是被动打开方。 syn_sent: syn package has been sent 五、握手完成:开始TCP 数据传输TCP 数据传输就是两我的隔空对话,差了一点距离,因此须要对方反复确认听见了本身的话。 <ignore_js_op> ![]() 张三喊了一句话(data),李四听见了以后要向张三回复本身听见了(ack)。 若是张三喊了一句,半天没听到李四回复,张三就认为本身的话被大风吹走了,李四没听见,因此须要从新喊话,这就是tcp重传。 也有多是李四听到了张三的话,可是李四向张三的回复被大风吹走了,以致于张三没听见李四的回复。张三并不能判断到底是本身的话被大风吹走了仍是李四的回复被大风吹走了,张三也不用管,重传一下就是。 既然会重传,李四就有可能同一句话听见了两次,这就是「去重」。「重传」和「去重」工做操做系统的网络内核模块都已经帮咱们处理好了,用户层是不用关心的。 <ignore_js_op> ![]() 张三能够向李四喊话,一样李四也能够向张三喊话,由于tcp连接是「双工的」,双方均可以主动发起数据传输。不过不管是哪方喊话,都须要收到对方的确认才能认为对方收到了本身的喊话。 张三多是个高射炮,一说连说了八句话,这时候李四能够不用一句一句回复,而是连续听了这八句话以后,一块儿向对方回复说前面你说的八句话我都听见了,这就是批量ack。可是张三也不能一次性说了太多话,李四的脑子短期可能没法消化太多,两人之间须要有协商好的合适的发送和接受速率,这个就是「TCP窗口大小」。 网络环境的数据交互同人类之间的对话还要复杂一些,它存在数据包乱序的现象。同一个来源发出来的不一样数据包在「网际路由」上可能会走过不一样的路径,最终达到同一个地方时,顺序就不同了。操做系统的网络内核模块会负责对数据包进行排序,到用户层时顺序就已经彻底一致了。 六、TCP 四次挥手:“Say goodbye!”TCP断开连接的过程和创建连接的过程比较相似,只不过中间的两部并不老是会合成一步走,因此它分红了4个动做,张三挥手(fin)——李四伤感地微笑(ack)——李四挥手(fin)——张三伤感地微笑(ack)。 <ignore_js_op> ![]() 之因此中间的两个动做没有合并,是由于tcp存在「半关闭」状态,也就是单向关闭。张三已经挥了手,但是人尚未走,只是再也不说话,可是耳朵仍是能够继续听,李四呢继续喊话。等待李四累了,也再也不说话了,超张三挥了挥手,张三伤感地微笑了一下,才完全结束了。 <ignore_js_op> ![]() 上面有一个很是特殊的状态time_wait,它是主动关闭的一方在回复完对方的挥手后进入的一个长期状态,这个状态标准的持续时间是4分钟,4分钟后才会进入到closed状态,释放套接字资源。不过在具体实现上这个时间是能够调整的。 它就比如主动分手方要承担的责任,是你提出的要分手,你得付出代价。这个后果就是持续4分钟的time_wait状态,不能释放套接字资源(端口),就比如守寡期,这段时间内套接字资源(端口)不得回收利用。 它的做用是重传最后一个ack报文,确保对方能够收到。由于若是对方没有收到ack的话,会重传fin报文,处于time_wait状态的套接字会当即向对方重发ack报文。 同时在这段时间内,该连接在对话期间于网际路由上产生的残留报文(由于路径过于崎岖,数据报文走的时间太长,重传的报文都收到了,原始报文还在路上)传过来时,都会被当即丢弃掉。4分钟的时间足以使得这些残留报文完全消逝。否则当新的端口被重复利用时,这些残留报文可能会干扰新的连接。 4分钟就是2个MSL,每一个MSL是2分钟。MSL就是maximium segment lifetime——最长报文寿命。这个时间是由官方RFC协议规定的。至于为何是2个MSL而不是1个MSL,我尚未看到一个很是满意的解释。 四次挥手也并不老是四次挥手,中间的两个动做有时候是能够合并一块儿进行的,这个时候就成了三次挥手,主动关闭方就会从fin_wait_1状态直接进入到time_wait状态,跳过了fin_wait_2状态。 七、本文小结TCP状态转换是一个很是复杂的过程,本文仅对一些简单的基础知识点进行了类比讲解。关于TCP的更多知识还须要读者去搜寻相关技术文章进入深刻学习。若是读者对TCP的基础知识掌握得比较牢固,高级的知识理解起来就不会太过于吃力。 附录1:同类文章精选若是您以为本系列文章过于基础,您可直接阅读如下系列:
《鲜为人知的网络编程》系列文章为高阶必读,该系列目录以下:
关于移动端网络特性及优化手段的总结性文章请见:
附录2:参考资料《TCP/IP详解 - 第11章·UDP:用户数据报协议》 《TCP/IP详解 - 第17章·TCP:传输控制协议》 《TCP/IP详解 - 第18章·TCP链接的创建与终止》 《TCP/IP详解 - 第21章·TCP的超时与重传》 《通俗易懂-深刻理解TCP协议(上):理论基础》 《通俗易懂-深刻理解TCP协议(下):RTT、滑动窗口、拥塞处理》 《理论经典:TCP协议的3次握手与4次挥手过程详解》 《理论联系实际:Wireshark抓包分析TCP 3次握手、4次挥手过程》 《计算机网络通信协议关系图(中文珍藏版)》 《高性能网络编程(一):单台服务器并发TCP链接数到底能够有多少》 《高性能网络编程(二):上一个10年,著名的C10K并发链接问题》 《高性能网络编程(三):下一个10年,是时候考虑C10M并发问题了》 《高性能网络编程(四):从C10K到C10M高性能网络应用的理论探索》 《简述传输层协议TCP和UDP的区别》 《为何QQ用的是UDP协议而不是TCP协议?》 《移动端即时通信协议选择:UDP仍是TCP?》 《技术往事:改变世界的TCP/IP协议(珍贵多图、手机慎点)》 《UDP中一个包的大小最大能多大?》 《Java新一代网络编程模型AIO原理及Linux系统AIO介绍》 《NIO框架入门(一):服务端基于Netty4的UDP双向通讯Demo演示》 《NIO框架入门(二):服务端基于MINA2的UDP双向通讯Demo演示》 《NIO框架入门(三):iOS与MINA二、Netty4的跨平台UDP双向通讯实战》 《NIO框架入门(四):Android与MINA二、Netty4的跨平台UDP双向通讯实战》 《P2P技术详解(一):NAT详解——详细原理、P2P简介》 《P2P技术详解(二):P2P中的NAT穿越(打洞)方案详解》 《P2P技术详解(三):P2P技术之STUN、TURN、ICE详解》 《通俗易懂:快速理解P2P技术中的NAT穿透原理》 >> 更多同类文章 …… |