TCP连接管理

TCP运输连接有3个阶段, 即: 连接建立,数据传送和连接释放。

1. TCP的连接建立(3次握手)

TCP连接的建立采用客户服务器方式。主动发起连接建立的应用进程叫做客户(client), 而被动等待连接建立的应用进程叫做服务器(server)。

TCP是面向连接的,无论哪一方向另一方发送数据之前,都必须先在双方之间建立一条连接。在TCP/IP协议中,TCP 协议提供可靠的连接服务,连接是通过三次握手进行初始化的。

看图讲解。

1.第一次握手:建立连接。客户端(A)发送连接请求报文段, SYN置为1,seq(Sequence Number)=x。TCP规定,SYN报文段(SYN为1,ACK为0的报文段)不能携带数据,但要消耗掉一个序号。然后,客户端进入SYN-SENT(同步已发送)状态,等待服务器的确认。

2.第二次握手:服务器(B)收到SYN报文段。服务器收到客户端的SYN报文段,还需要对这个SYN报文段进行确认。SYN置为1,ACK置为1(可以到第一章头部信息查看这样代表什么意思),ack(Acknowledgment Number)=x+1(seq+1),seq=y,服务器端将上述所有信息放到一个报文段中(这个报文段也不能携带数据,但同样要消耗一个序号),一并发送给客户端,此时服务器进入SYN-RECVD状态;

3.第三次握手:客户端收到服务器的SYN+ACK报文段。然后将seq设置为x+1(下一个报文段),ack设置为y+1,向服务器发送ACK报文段(即SYN为0,ACK为1的报文段),这个报文段发送完毕以后,客户端进入ESTABLISHED状态,服务器端收到确认后,也进入ESTABLISHED状态,完成TCP三次握手。

为什么客户端A还要发送一次确认,进行第3次握手呢?主要是为了防止"已失效的连接请求报文段"突然又传到了服务端B,因为产生错误。

所谓"已失效的连接请求报文段"是这样产生的:

一种正常情况。A发出连接请求,但因连接请求报文丢失而未收到确认。于是A再重传一次连接,然后收到了重传连接的确认,建立连接,数据传输完毕,释放了连接。由于第一个是丢失了,第二个到达了B,所以没有"已失效的连接请求报文段"。

第二种异常情况。即A发出的第一个请求没有丢失,而是在某个网络节点滞留了,以致延误到连接释放以后的某个时间才到达B。本来就是一个失效的报文段。但B收到此失效的连接请求报文段后,就误认为是A又发出一次新的连接请求。新的连接就建立了。

由于现在A并没有发出连接请求,因此不会理睬B的确认,也不会向B发送数据。而B以为新的运输连接已经建立了,并一直等待A发来数据。B的许多资源就这样白白浪费了。

而A发送第三次握手,就可以防止上述现象的发送:

就上述情况,A不会向B的第二次握手发出确认。B由于收不到确认,超时后就不会为此建立连接。

2. TCP的连接释放(4次挥手)

先上图,有图说得更清楚。

步骤:

1. 挥手1: 首先客户端A发送释放连接报文段: FIN置为1, seq=已传送最后一个字节的序号+1,并停止再发送数据。这时A进入FIN-WAIT-1(终止等待1)状态,等待服务器B的确认。FIN报文段即时不携带数据,它也消耗一个序号!

2. 挥手2: 服务器B收到连接释放报文段后发出确认报文段: ACK置为1,seq=v,ack=u+1。然后B进入CLOSE-WAIT(关闭等待)状态。这时TCP的连接处于半关闭(half-close)状态,即A已经没有数据发送来,若B发送数据,A仍要接收。

3. 客户端A收到B的确认报文段后,进入FIN-WAIT-2(终止等待2)状态。等待B发出的连接释放报文段。

4. 挥手3: 如果B已经没有要向A发送的数据,B就发出连接释放报文段: FIN、ACK置为1,seq=w(在半关闭状态的B可能还发送来一些数据),ack=u+1(必须重复上一次已发送过的确认号)。这时B进入LAST-ACK(最后确认)状态,等待A的确认。(如果在第一次挥手后,B没有数据需要A接收,那就直接进行第三次挥手,这样,四次挥手就变成了三次挥手了)

5. 挥手4: A在收到B的连接释放报文段后,发出确认: ACK置为1,ack=w+1,seq=u+1(步骤1那已经消耗了一个序号,所以这里是u+1)。然后进入TIME-WAIT(时间等待)状态。B收到这个确认后进入CLOSED状态,关闭连接。

注意,现在TCP连接还没有释放掉,必须在经过时间等待计时器(TIME-WAIT timer)设置的时间2MSL(时间MSL叫最长报文段寿命,RFC793建议设为2分钟)后,A才进入CLOSED状态。

为什么A在TIME-WAIT状态必须等待2MSL,一共就是4分钟这么长呢?

1. 为了保证A发送的最后一个ACK能到达B!

因为这个ACK报文段有可能丢失,B就一直处于LASK-ACK状态,然后B超时重传第三次挥手发送的FIN+ACK连接释放报文段,这时A就能在2MSL时间内收到这个重传的FIN+ACK报文段。然后A就在重传一次挥手4发送的连接ACK报文段,再重新启动2MSL计时器。最后A和B就都能正常进入到CLOSED状态。

2. 防止3次握手中提到的"已失效的连接请求报文段"出现!

A发送完最后一次ACK报文段后,再经过2MSL,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样就可以使下一个新的连接中不会出现这种旧的连接请求报文段。

通过下面例子说明:

假设tcp连接是: A(1.2.3.4:8888)------B(6.7.8.9:9999), 这就是一个tcp四元组。 当tcp连接关闭后, 四元组释放。 后面的新连接可能会重用到这个四元组(有这个可能性), 那么问题就来了: 新四元组和旧四元组完全一致, 他们的网络包会混乱吗? 所以, 可以考虑这样一个机制: 让旧四元组对应的所有网络包都消失后(等一段时间), 才允许新四元组建立, 颇有点锁的味道。

保活计时器(keepalive timer)

除了上述提到的时间等待计时器外,TCP还设有一个保活计时器!

设想这样种情况: 客户端主动与服务端建立TCP连接后,过了一段时间,客户端机器突然故障宕机了!服务端就再也无法收到客户端发来的数据,服务器不能白白干等着!保活计时器就是解决这个问题的:服务端每收到一次客户的数据,就重新设置保活计时器,时间的设置通常是2小时。

若2小时内没有收到客户端的数据,服务器还是不会放弃它的!就会发送一个探测保文段,以后每隔75分钟发送一次。若连续发送了10次探测保文段后,客户端仍无响应,服务器就认为客户端出现了故障,然后就关闭了这个连接。

TCP学习总结(四)的更多相关文章

  1. redis学习教程四《管理、备份、客户端连接》

    redis学习教程四<管理.备份.客户端连接>  一:Redis服务器命令 Redis服务器命令 下表列出了与Redis服务器相关的一些基本命令. 序号 命令 说明 1 BGREWRITE ...

  2. Java IO学习笔记四:Socket基础

    作者:Grey 原文地址:Java IO学习笔记四:Socket基础 准备两个Linux实例(安装好jdk1.8),我准备的两个实例的ip地址分别为: io1实例:192.168.205.138 io ...

  3. Netty 学习(四):ChannelHandler 的事件传播和生命周期

    Netty 学习(四):ChannelHandler 的事件传播和生命周期 作者: Grey 原文地址: 博客园:Netty 学习(四):ChannelHandler 的事件传播和生命周期 CSDN: ...

  4. 从零开始学习jQuery (四) 使用jQuery操作元素的属性与样式

    本系列文章导航 从零开始学习jQuery (四) 使用jQuery操作元素的属性与样式 一.摘要 本篇文章讲解如何使用jQuery获取和操作元素的属性和CSS样式. 其中DOM属性和元素属性的区分值得 ...

  5. 前端学习 第四弹: HTML(一)

    前端学习 第四弹: HTML(一) 元素分类:块元素 内联元素 块级元素在浏览器显示时,通常会以新行来开始(和结束). 例子:<h1>, <p>, <ul>, &l ...

  6. C#可扩展编程之MEF学习笔记(四):见证奇迹的时刻

    前面三篇讲了MEF的基础和基本到导入导出方法,下面就是见证MEF真正魅力所在的时刻.如果没有看过前面的文章,请到我的博客首页查看. 前面我们都是在一个项目中写了一个类来测试的,但实际开发中,我们往往要 ...

  7. Android Animation学习(四) ApiDemos解析:多属性动画

    Android Animation学习(四) ApiDemos解析:多属性动画 如果想同时改变多个属性,根据前面所学的,比较显而易见的一种思路是构造多个对象Animator , ( Animator可 ...

  8. 五、Android学习第四天补充——Android的常用控件(转)

    (转自:http://wenku.baidu.com/view/af39b3164431b90d6c85c72f.html) 五.Android学习第四天补充——Android的常用控件 熟悉常用的A ...

  9. 四、Android学习第四天——JAVA基础回顾(转)

    (转自:http://wenku.baidu.com/view/af39b3164431b90d6c85c72f.html) 四.Android学习第四天——JAVA基础回顾 这才学习Android的 ...

随机推荐

  1. PHP 如何获取客户端ip地址

    PHP 如何获取客户端ip地址 一.总结 一句话总结:主要是使用$_SERVER的 REMOTE_ADDR 和 HTTP_X_FORWARDED_FOR 两个属性,在用户使用不同代理的时候这两个属性可 ...

  2. python基础知识点(unittest)

    目录: unittest 单元测试框架 1.写用例: Testcase 2.执行:TestSuite 类 TestLoader 类 3.比对结果(期望值/实际值):断言函数 4.结果:TestText ...

  3. Venom- Eminem

    I got a song filled with shit for the strong willed. 我写了一首充满戾气的歌献给意志坚强的人. When the world give you a ...

  4. [大数据面试题]hadoop核心知识点

    * 面试答案为LZ所写,如需转载请注明出处,谢谢. * 这里不涉及HiveSQL和HBase操作的笔试题,这些东西另有总结. 1.MR意义. MR是一个用于处理大数据的分布式离线计算框架,它采用”分而 ...

  5. centos 7 安装二进制mysql 详细步骤

    1 下载地址:https://cdn.mysql.com//Downloads/MySQL-5.7/mysql-5.7.24-linux-glibc2.12-x86_64.tar.gz 复制这个链接在 ...

  6. 解决angular ui-grid 中添加input date修改日期

    需求:在angular ui-grid列表中添加一个日期组件来修改时间. 在angular ui-grid添加了一个html5 date input,后端返回的数据是YYYY-MM-DD,比如:201 ...

  7. React文档(十八)最佳性能

    在内部,React使用好几种聪明的技巧去最小化更新UI所需要的DOM操作.对于很多应用来说,使用React会使得构建用户界面非常之快而且不需要做太多专门的性能优化.虽然如此,还是有一些方法可以让你为R ...

  8. linux命令:使用less从后向前查看日志信息

    线上出问题的时候,我们常用tail-n 或者tail-f或者grep或者vicat等各种命令去查看异常信息,但是日志是在不停地刷屏,tail是动态的在变的,我们往往期望从日志最后一行往前一页一页的翻页 ...

  9. Vagrant 入门指南

    https://blog.csdn.net/qianghaohao/article/details/80038096 https://blog.csdn.net/happyhorizion/artic ...

  10. .NET 控件的认识。

    四单元的题目里面,涉及了很多之前没有用过的控件的使用,前12道题都不是很难,所以很快做完了 ,但是后面的因为timer控件找不到,有些操作无法实现,所以就没做,但是也是认真的看了的. 等什么时候把ti ...