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. filesystem type ntfs not configured in kernel

    移动硬盘是NTFS格式的,挂载时候kernel不支持这格式 出现:filesystem type ntfs not configured in kernel 解决:通过sudo yum install ...

  2. 使用 requests 模块

    官网:http://docs.python-requests.org/en/master/ 请求方式 requests.get() requests.post() requests.put() req ...

  3. linux上docker安装centos7.2

    1.安装 docker pull centos:7.2.1511 2.启动镜像 docker run -d -i -t <IMAGE ID> /bin/bash 3.进入容器 docker ...

  4. C++标准模板库(STL)之Priority_Queue

    1.Priority_Queue的常用用法 priority_queue:优先队列,底层是使用堆来实现的.优先队列中,队首元素一定是当前队列中优先级最高的哪一个. a (优先级3),b(优先级4),c ...

  5. 配置python3

    1. 下载解压.$ wget https://www.python.org/ftp/python/3.4.1/Python-3.4.1.tgz$ tar zxvf Python-3.4.1.tgz 2 ...

  6. 老男孩Python九期全栈学习笔记4

    ---恢复内容开始--- day4 1.作业回顾 1.有变量name = 'aleX leNb',完成如下操作: 1)移除 name 变量对应的值两边的空格,并输出处理结果 2)移除 name 变量左 ...

  7. 【转】依赖注入的威力,.NET Core的魅力:解决MVC视图中的中文被html编码的问题

    有园友在博问中提了这样一个问题 —— .NET Core 中文等非英文文字html编码输出问题,到我们的 ASP.NET Core 项目中一看,也是同样的问题. 比如下面的Razor视图代码: @{ ...

  8. vim 插件 -- taglist

    taglist 插件是基于ctags生成的tags文件一个工具.主要是用来生成当前文件的结构.如:函数名.变量名结构.具体如下图: 下载 https://www.vim.org/scripts/scr ...

  9. Python运行时的常见错误

    1)忘记在 if , elif , else , for , while , class ,def 声明末尾添加冒号(:)(导致 “SyntaxError :invalid syntax”) 2)使用 ...

  10. Tensorflow计算加速

    在tensorflow里可以通过tf.device函数来指定每个运行的设备,可以是GPU也可以是CPU,比如CPU在tensorflow里的名称为/cpu:0,即便电脑里有多个CPU,tensorfl ...