TCP协议是TCP/IP体系中核心一个协议,该协议比起IP协议,ICMP协议,UDP协议都更复杂,因此这篇文章主要分析TCP协议在建立连接和断开连接的时候,状态转移以及报文段的内容。
下面,先放一张TCP的状态转移图:

TCP协议之三次握手

三次握手的过程是TCP在客户端和服务端建立连接的过程。简单的来说三次握手过程,就是客户端先发送一个连接请求给服务端,这是第一次握手。服务端接收到客户端发来的链接请求,然后在将确认的消息发给客户端,这是第二次握手。客户端对服务端发来的确认消息进行确认,然后将确认的消息发给服务端,这就是三次握手。三次握手之后,链接建立。
为什么一定是三次握手才能建立一个可靠地链接?如果不是三次握手,那么在客户端发送了链接请求之后,服务端对这个请求进行确认,就认定这次的链接已经成功建立,俗称的二次握手。这样的方式的弊端在哪里?
考虑这么一种情况,当客户端进行第一次握手时,发送了一个报文段,但是这个报文段因为网络的问题,迟迟没有到,这时,客户端又会再一次发送一个连接请求的报文段给服务端,这次成功接收,两者建立连接,并通信结束,关闭连接。这之后,因为网络延迟的那个报文段传到了服务端那里,服务端又以为客户端要建立新的连接,于是就同意了,向客户端发送确认。因为是二次握手,所以服务端后续要做的事情,就是等待客户端发送的消息,但是客户端是不会理会服务端传来的确认,所以服务端就会一直在等待客户端的数据,白白浪费了资源。

抓包分析TCP三次握手的报文段

现在,详细说一下三次握手具体是做了什么。
第一次握手,客户端发送一个报文段给服务端,该报文段中标志有SYN标志,该标志表示建立连接,以及一个初始的序列号。
第二次握手时,服务端发送一个报文段给客户端,该报文段中标志有SYN标志,和ACK标志。ACK标志的值是客户端发来的初始序号值+ 1,表示对客户端进行确认,报文段中还有服务端自己的初始序号。
第三次握手时,客户端发送一个报文段给服务端,该报文段中标志只有ACK标志,该ACK值是服务端的初始序列化的值 + 1,表示对服务端进行确认,以及还有一个序号值,该序号值为客户端第一次握手时的序号值 + 1。
三次握手建立连接结束。

图片上共有三行,每一行代表一次握手。我们先看第一行

可以看出,第一次握手时55732端口的程序主动发送一个建立链接的报文段给8888端口。这个55732端口是Java程序写的一个Socket客户端,8888端口是Socket程序写的服务端。建立连接的报文段,Flags中,只有SYN是为1的,这表明这是一个建立连接的报文段,该报文段中初始的序列号为0,ACK的number也为0。

第二次握手,是服务端发送给客户端一个报文段,表示确认收到了客户端的链接请求。该报文段中标志位有两个一个是ACK,一个SYN。表示收到链接请求,端口开放。该报文段中也会发送一个服务端自己的初始序列号。注意,这里ACK的值变成了1,是客户端初始序列号 + 1才有的。

第三次握手,是客户端发送给服务端一个报文段,表示确认收到了服务端的确认。因为双方端口都已经打开,所以客户端在发,就不会再有SYN标志了,这里只有ACK标志,该标志的值也是1,是因为服务端的初始序列号 + 1造成的。这里的序列号为1,是因为第一次握手,发送了一个SYN标志,该标志会占用1个序号值,但是ACK不会。
对应到上面的状态图中,就是客户端是主动打开,从起始点发送SYN报文段,进入SYN_SENT状态,然后接受SYN,ACK,走黑粗线的路径进入到数据传输状态,也就是ESTABLISHED,对于服务端而言,就是从起始点走虚线的部分,被动打开后,接受客户端的SYN,进入SYN_RCVD,最后,接受客户端第三次握手的ACK,进入数据传输状态,也就是ESTABLISHED。

TCP协议之四次挥手

TCP协议是一种全双工协议,拥有半关闭的特性。

全双工的意思是A可以往B发送数据,B同时也可以给A发送数据。
半双工的意思是A可以往B发送数据,B也可以给A发送数据,但是两者不能同时。
单工的意思是只能A给B发送数据,或者B给A发送数据。
半关闭的意思是将全双工,变成单工,也就是如果B关闭,是指B不能给A发数据了,但是A可以给B发

所以TCP协议如果要正常的关闭客户端与服务端的链接,需要四次报文段,也就是4次挥手。
首先,客户端因为应用程序的执行完毕,会主动开始断开链接,这时会发送一个含有FIN标志位的报文段。这表明客户端不会再发送数据给服务端。这时第一次挥手。
然后,服务端接收到这个报文段,就会发送一个含有ACK标志的报文段给客户端,表示确认收到了关闭的报文段。这是第二次挥手。
然后,服务端在处理完服务端的事情后,也会发送一个含有FIN的报文段给客户端,表示服务端不会再发送数据给客户端。这是第三次挥手。
最后,客户端收到这个报文段后,就会发送一个含有ACK的报文段给服务端,表示确认收到了关闭的报文段。这是第四次挥手。至此,链接全部关闭。

抓包分析TCP四次挥手的报文段


不用看黑色报文,4行代表关闭的4次挥手的过程,每一行是一次挥手。
第一行,是客户端主动关闭链接,发送一个含有FIN的报文段,这是第一次挥手
第二行,是服务端确认客户端的FIN报文,发送一个ACK的确认报文,该ACK的值是9,而第一行的序列号的8,因为与SYN一样,FIN也占一个序列号。
忽略黑的后第三行,服务端发送一个含有FIN的报文段,这是第三次挥手。
第四行,客户端会这个FIN报文段进行确认,发送了一个ACK报文段。该ACK的值是第三行的序列号 + 1。

对应到上面的状态图中,先说服务端的状态转移,因为收到了客户端的FIN,所以发送一个ACK给客户端,同时自己进入到CLOSE_WAIT状态,等待服务端应用程序结束,发送FIN给客户端,自己进入LAST_ACK状态,等待最后的ACK到来,接收到ACK,结束状态。

客户端因为先发起关闭,状态比较复杂,他先发送一个FIN给服务端,自己进入了FIN_WAIT_1状态,这时他等待接收服务端的报文,该报文会有三种可能:

  1. 只有服务端的ACK
  2. 只有服务端的FIN
  3. 基于服务端的ACK,又有FIN

对于第一种,该ACK是服务端确认了客户端的FIN而发的,这时客户端会进入FIN_WAIT_2状态,这是当他收到服务端的FIN来时,发送了一个ACK,会进入到TIME_WAIT状态,他要在这个状态等待2MSL的时间,1个MSL是报文段在网络的最长时间,客户端等待2MSL,是为了当最后一个ACK丢失时,可以在发送一次,因为这时,服务端在等待超时后在发送一个FIN给客户端,所以客户端也知道了ACK丢失了。

对于第二种,只有服务端的FIN的时,会发送一个ACK给服务端,客户端进入CLOSING状态,然后接收到服务端的ACK时,也会进入TIME_WAIT状态。

对于第三种,同时都收到了,就省略了进入CLOSING状态,直接进入TIME_WAIT状态。抓包分析的截图,就是这种情况。

TCP协议之三次握手与四次挥手的更多相关文章

  1. TCP协议三次握手与四次挥手通俗解析

    TCP/IP协议三次握手与四次握手流程解析 一.TCP报文格式 TCP/IP协议的详细信息参看<TCP/IP协议详解>三卷本.下面是TCP报文格式图: 图1 TCP报文格式 上图中有几个字 ...

  2. TCP协议三次握手与四次挥手详解

    在计算机网络的学习中TCPi协议与Http协议是我们必须掌握的内容,其中Tcp协议属于传输层,而Http协议属于应用层,本博客主要讲解Tcp协议中的三次握手与四次挥手,关于Http协议感兴趣的可以参看 ...

  3. TCP协议三次握手和四次挥手

    http://www.cnblogs.com/rootq/articles/1377355.html TCP(Transmission Control Protocol) 传输控制协议 TCP是主机对 ...

  4. TCP/IP之三次握手、四次挥手

    参照:http://www.cnblogs.com/hnrainll/archive/2011/10/14/2212415.html 在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建 ...

  5. TCP协议三次握手、四次挥手

    TCP的概述 TCP 把连接作为最基本的对象,每一条 TCP 连接都有两个端点,这种断点我们叫作套接字(socket),它的定义为端口号拼接到 IP 地址即构成了套接字,例如,若 IP 地址为 192 ...

  6. TCP协议三次握手、四次挥手过程

    本文通过图来梳理TCP-IP协议相关知识.TCP通信过程包括三个步骤:建立TCP连接通道,传输数据,断开TCP连接通道.如图1所示,给出了TCP通信过程的示意图. 上图主要包括三部分:建立连接.传输数 ...

  7. TCP协议“三次握手”与“四次挥手”详解(下)

    前面进行“三次握手”建立连接后,当客户端的数据发送完毕,它就会要求与服务器端断开连接,那么就要进行“四次挥手”进行连接的释放. 注意,此处所谓的“客户端”与“服务器端”,只是为了方便标识连接的双方,即 ...

  8. TCP协议“三次握手”与“四次挥手”详解(上)

    在使用TCP协议进行数据的传输之前,客户端与服务器端需要建立TCP Connection,即建立连接,之后两端才能进行数据的传输. 下面堆TCP连接“三次握手”的过程进行说明. 1.相关概念 首先,我 ...

  9. TCP/IP协议三次握手和四次挥手大白话解说

    前言 昨天晚上被一位师傅问到了TCP/IP的工作机制,心里很清楚三次握手,然而对于四次挥手却忘了,这是大学习里学过的,奋而翻阅书籍和网络对之前所学的做一个温顾,算是夯实自我吧. TCP(Transmi ...

随机推荐

  1. iOS 容器控制器 (Container View Controller)

    iOS 容器控制器 (Container View Controller) 一个控制器包含其他一个或多个控制器,前者为容器控制器 (Container View Controller),后者为子控制器 ...

  2. php中 0 与 字符串比较的问题

    今天我的技术群里,被一个很不起眼的问题炸出很多基础不稳的phper,就是这么一句 : <?php if(0 == 'yes'){ echo 'yes'; }else{ echo 'no'; } ...

  3. Docker实战--部署简单nodejs应用

    如何在Docker的container里运行Node.js程序 主体思路:一个简单的Node.js web app,来构建一个镜像,然后基于这个镜像,运行一个容器,从而实现快速部署. 操作环境: 虚拟 ...

  4. [MongoDB] - 数据的增删改操作

    在前一篇中简单的介绍了一些基本操作命令,现在分别针对这些命令进行比较详细的说明: 一.数据插入 插入数据使用命令insert,insert的参数只有一个,就是要插入的文档BSON数据.MongoDB的 ...

  5. 如何在 Windows上编译Objective-C

    Objective-C现在几乎已经变成了苹果的专利了,可以直接在苹果的Xcode上编译Objective-C程序,但是在Windows平台下的编译工具就寥寥无几了,本身这种语言用的人就不是很多.今天在 ...

  6. unity Editor的使用

    1.首先定义一个需要控制数值的类,类中定义若干个变量 using UnityEngine;using System.Collections; using UnityEngine; using Syst ...

  7. android学习12——重载SurfaceView一些方法的执行顺序

    先看代码 public class SurfaceViewActivity extends Activity { @Override public void onCreate(Bundle saved ...

  8. 三种预处理器px2rem

    CSS单位rem 在W3C规范中是这样描述rem的: font size of the root element. 移动端越来越多人使用rem,推荐淘宝开源框架lib-flexible 今天来介绍一下 ...

  9. Laravel中间件

    先谈一谈中间件的使用场景,比如路由转到一张页面,我们需要记录用户的cookie,或者检测用户的访问权限,这些操作如果全写在控制器里是不合适的,因为随着业务的扩充,控制器里的业务逻辑会越来越臃肿,难以维 ...

  10. smarty模板基础3 *缓存数据*

    缓存数据,这个并不是暂存的缓存,而是写入了内存的缓存 通过一个例子来书写:缓存数据 一.书写php和html页面的基本功能 既然是用smarty模板,那么前端和后端要分开写了 (1)php页面 < ...