TCP协议全称为:Transmission Control Protocol,是一种面向链接、保证数据传输安全、可靠的数据传输协议。为了确保数据的可靠传输,不仅需要对发出的每个字节进行编号确认,还需要验证每一个数据包的有效性。每个TCP数据包是封闭在IP包中的,每个一IP包的后面紧跟着的是TCP头,TCP报文格式如下:

源端口和目的端口字段

  • TCP源端口(Source Port):源计算机上的应用程序的端口号,占 16 位。
  • TCP目的端口(Destination Port):目标计算机的应用程序端口号,占 16 位。

序列号字段

CP序列号(Sequence Number):占 32 位。它表示本报文段所发送数据的第一个字节的编号。在 TCP 连接中,所传送的字节流的每一个字节都会按顺序编号。当SYN标记不为1时,这是当前数据分段第一个字母的序列号;如果SYN的值是1时,这个字段的值就是初始序列值(ISN),用于对序列号进行同步。这时,第一个字节的序列号比这个字段的值大1,也就是ISN加1。

确认号字段

TCP 确认号(Acknowledgment Number,ACK Number):占 32 位。它表示接收方期望收到发送方下一个报文段的第一个字节数据的编号。其值是接收计算机即将接收到的下一个序列号,也就是下一个接收到的字节的序列号加1。

数据偏移字段

TCP 首部长度(Header Length):数据偏移是指数据段中的“数据”部分起始处距离 TCP 数据段起始处的字节偏移量,占 4 位。其实这里的“数据偏移”也是在确定 TCP 数据段头部分的长度,告诉接收端的应用程序,数据从何处开始。

保留字段

保留(Reserved):占 4 位。为 TCP 将来的发展预留空间,目前必须全部为 0。

标志位字段

  • CWR(Congestion Window Reduce):拥塞窗口减少标志,用来表明它接收到了设置 ECE 标志的 TCP 包。并且,发送方收到消息之后,通过减小发送窗口的大小来降低发送速率。
  • ECE(ECN Echo):用来在 TCP 三次握手时表明一个 TCP 端是具备 ECN 功能的。在数据传输过程中,它也用来表明接收到的 TCP 包的 IP 头部的 ECN 被设置为 11,即网络线路拥堵。
  • URG(Urgent):表示本报文段中发送的数据是否包含紧急数据。URG=1 时表示有紧急数据。当 URG=1 时,后面的紧急指针字段才有效。
  • ACK:表示前面的确认号字段是否有效。ACK=1 时表示有效。只有当 ACK=1 时,前面的确认号字段才有效。TCP 规定,连接建立后,ACK 必须为 1。
  • PSH(Push):告诉对方收到该报文段后是否立即把数据推送给上层。如果值为 1,表示应当立即把数据提交给上层,而不是缓存起来。
  • RST:表示是否重置连接。如果 RST=1,说明 TCP 连接出现了严重错误(如主机崩溃),必须释放连接,然后再重新建立连接。
  • SYN:在建立连接时使用,用来同步序号。当 SYN=1,ACK=0 时,表示这是一个请求建立连接的报文段;当 SYN=1,ACK=1 时,表示对方同意建立连接。SYN=1 时,说明这是一个请求建立连接或同意建立连接的报文。只有在前两次握手中 SYN 才为 1。
  • FIN:标记数据是否发送完毕。如果 FIN=1,表示数据已经发送完成,可以释放连接。

窗口大小字段

窗口大小(Window Size):占 16 位。它表示从 Ack Number 开始还可以接收多少字节的数据量,也表示当前接收端的接收窗口还有多少剩余空间。该字段可以用于 TCP 的流量控制。

TCP 校验和字段

校验位(TCP Checksum):占 16 位。它用于确认传输的数据是否有损坏。发送端基于数据内容校验生成一个数值,接收端根据接收的数据校验生成一个值。两个值必须相同,才能证明数据是有效的。如果两个值不同,则丢掉这个数据包。Checksum 是根据伪头 + TCP 头 + TCP 数据三部分进行计算的。

紧急指针字段

紧急指针(Urgent Pointer):仅当前面的 URG 控制位为 1 时才有意义。它指出本数据段中为紧急数据的字节数,占 16 位。当所有紧急数据处理完后,TCP 就会告诉应用程序恢复到正常操作。即使当前窗口大小为 0,也是可以发送紧急数据的,因为紧急数据无须缓存。

可选项字段

选项(Option):长度不定,但长度必须是 32bits 的整数倍。

TCP建立连接

TCP建立连接需要三个步骤,也就是大家熟知的三次握手。下图了正常情形下通过三次握手建立连接的过程:

  • A机器发出一个数据包SYN设置为1,表示希望建立连接。这个包中的假设seq为x

    • 机器A发送SYN数据包后,会进入SYN_SENT状态
  • B机器收到A发送的SYN数据后,响应一个数据包将SYNACK设置为1,假设这个响应包的序列号为y,同时期望下一次收到的数据库的序列为x+1
    • B回复响应包后,进入SYN_RECD状态
  • A收到B的响应包后,对响应包做应答将ACK标志设置为1,序列号为x + 1,期望下一次收到的数据包的序列号为y+1
    • A机器和B机器连接建立成功

TCP三次握手抓包验证

以为验证三次握手是否描述正确,在下使用Wireshark进行抓包验证。首先使用ping命令获取www.baidu.com的ip地址:

正在 Ping www.a.shifen.com [183.232.231.174] 具有 32 字节的数据:
来自 183.232.231.174 的回复: 字节=32 时间=16ms TTL=54
来自 183.232.231.174 的回复: 字节=32 时间=16ms TTL=54
来自 183.232.231.174 的回复: 字节=32 时间=16ms TTL=54 183.232.231.172 的 Ping 统计信息:
数据包: 已发送 = 3,已接收 = 3,丢失 = 0 (0% 丢失),
往返行程的估计时间(以毫秒为单位):
最短 = 16ms,最长 = 16ms,平均 = 16ms

以上输出显示www.baidu.com的ip地址: 183.232.231.174,然后使用Wireshark的过滤器仅显示与www.baidu.com通信的tcp数据包:

ip.src_host == "183.232.231.174" or ip.dst_host == "183.232.231.174" and tcp

使用Wireshark抓包分析后,验证TCP正常连接三次握手与上节描述的一致。

为什么是三次握手?

为什么是三次握手?三次握手主要有两个目的:信息对等防止超时

信息对等

两台机器通信时都需要确认四个信息:

  • 自己发报文的能力
  • 自己收报文的能力
  • 对方发报文的能力
  • 对方收报文的通知
第一次握手

第一次握手A机器向B机器发送SYN数据包,此时只有B机器能确认自己收报文的能力对方发报文的能力

一次握手完成B机器能够确认的信息有:

  • [x] B机器收报文的能力
  • [x] A机器发报文的能力
第二次握手

每二次握手后B响应A机器的SYN数据包,此时A机器就能确认:自己发报文的能力自己收报文的能力对方发报文的能力对方收报文的能力

二次握手完成A机器能够确认的信息有:

  • [x] A机器发报文的能力
  • [x] A机器收报文的能力
  • [x] B机器发报文的能力
  • [x] B机器收报文的能力
第三次握手

每三次握手后A应答B机器的SYN + ACK数据包,此时B机器就能确认:自己发报文的能力对方收报文的能力

二次握手完成A机器能够确认的信息有:

  • [x] B机器发报文的能力
  • [x] A机器收报文的能力

至此经过三次握手A、B机器就能做到信息对等,双方都能确认自己和对方的收、发报文的能力,最后方便理解将信息对等制作成一个小表格:

防止超时

三次握手除了保证信息对等也是了防止请求超时导致脏连接。TTL网络报文的生存往往会超过TCP请求超时时间,如果两次握手就能创建连接,传输数据并释放连接后,第一个超时的连接请求才到达B机器,B机器 会以为是 A 创建新连接的请求,然后确认同意创建连接。因为A机器的状态不是SYN_SENT,所以会直接丢弃了B的确认数据,导致 B 机器单方面的创建连接完毕。

如果是三次握手,则 B 机器收到连接请求后,同样会向 A 机器确同意创建连接,但因为 A 不是SYN_SENT状态,所以 A机器 不会回复 B 机器确认创建连接请求,而 B 机器到一段时间后由于长时间没有收到确认信息,最终会导致连接创建失败,因此不会出现脏连接。

TCP断开连接

TCP是全双工通信,双方都能作为数据的发送方和接收方,但TCP会有断开的时候。TCP建立连接需要三次握手而断开连接却要四次,如图所示为TCP断开连接四次挥手过程:

  • A 机器发送关闭数据包将FIN设置为1,假设序列号为u,发完关闭数据包后此时 A 机器处理FIN_WAIT_1状态
  • B 收到关闭连接请求后,通知应用程序处理完剩下的数据
  • B 响应 A 的关闭连接请求,将ACK标志设置为1,seq为v,ack为u+1,随后 B 机器处于 CLOSE_WAIT状态
  • A 收到应答后,处于FIN_WAIT_2状态,继续等待 B 机器的FIN数据包
  • B 处理好现场后,主动向 A 机器发送数据包,并将FINACK标志设置为1,seq为w,ack为u+1,随后处于LAST_WAIT状态等待 A 机器的应答
  • A 机器收到FIN数据包后,随后发送ACK数据包,seq为u+1,ack为w+1, 此时 A 机器处理TIME_WAIT状态
  • B 机器收到ACK响应包后,进行CLOSED状态,连接正常关闭
  • A 机器在TIME_WAIT状态等待2MSL后,也进入CLOSEED状态,连接关闭

什么是2MSL:MSL是Maximum Segment Lifetime英文的缩写,中文可以译为“报文最大生存时间”,

2MSL即两倍的MSL

四次挥手断开连接可以用更形象的方式来表达:

  • 男生 :我们分手吧。
  • 女生 :好的,我需要去家里把东西收拾完,再发消息给你。(此时男生不能再拥抱女生)
  • 。。。,一个小时后
  • 女生 :我收拾完了,分手吧(此时女生也不能再拥抱男生)
  • 男生:好的(此时双方约定一段时间后,才可以分别找新的对象)

TCP四次挥手抓包验证

抓包过程与与三次握手抓包过程一致,这里不描述。直接看访问后抓包的截图:

  • 第一个包是由192.168.1.6这台机器(也就是客户机),发送了一个FIN包,seq为80,ack为2782
  • 第二个包由183.232.231.174(服务器),对192.168.1.6这台机器(也就是客户机)发送了一个ACK包,seq为2782,ack为81
  • 第三个包由183.232.231.174(服务器),对192.168.1.6这台机器(也就是客户机)发送了一个ACKFIN包,seq为2782,ack为81
  • 第四个包由192.168.1.6,向服务器响应了一个ACK包,seq为81,ack为2783

四次挥手流程与我们描述的一致。

TIME_WAIT 状态

主动要求关闭的机器(机器A)表示收到对方的FIN报文后,并发送出ACK报文后,进行TIME_WAIT状态,等待2MSL后进行CLOSED状态。如果在TIME_WAIT_1 时收到FIN标志和ACK标志报文时,可以直接进入TIME_WAIT状态,而无需进入TIME_WAIT_2状态。

为什么要有 TIME_WAIT

确认被动关闭(机器B)能够顺利进入CLOSED状态

假如A机器发送最后一个ACK后,但由于网络原因ACK包未能到达 B 机器,此时 B机器通常会认为 A机器 没有收到 FIN+ACK报文,会重发一次FIN+ACK报文。如果 A机器 发送最后一个ACK后,自私的关闭连接进入 CLOSED状态,就可能导致 B 无法收到ACK报文,无法正常关闭。

防止失效请求

TIME_WAIT 状态可以防止已失效的请求包与正常连接的请求数据包混淆而发生异常。因为TIME_WAIT 状态无法真正释放句柄资源,在此期间, Socket中使用的本地端口在默认情况下不能再被使用。

CLOSE_WAIT 状态

被动关闭的机器(机器B)在收到对方发送的,FIN报文后,马上回复ACK报文,进入CLOSE_WAIT状态。通知应用程序,处理剩下的数据,释放资源。

欢迎关注我的公众号:架构文摘,获得独家整理120G的免费学习资源助力你的架构师学习之路!

公众号后台回复arch028获取资料:

这次一定让你记住 TCP 三次握手、四手挥手!的更多相关文章

  1. [转]Linux服务器上11种网络连接状态 和 TCP三次握手/四次挥手详解

    一.Linux服务器上11种网络连接状态: 图:TCP的状态机 通常情况下:一个正常的TCP连接,都会有三个阶段:1.TCP三次握手;2.数据传送;3.TCP四次挥手. 注:以下说明最好能结合”图:T ...

  2. tcp三次握手四次挥手那些事

    建立TCP需要三次握手才能建立,而断开连接则需要四次挥手.三次握手,四次挥手流程图如下: 一.首先看下如何通过三次挥手----------建立连接 首先客户端发送连接请求报文,服务端接受连接后回复AC ...

  3. TCP三次握手四次挥手,通俗易懂版

    三次握手四次挥手 三次握手 其实很好理解,三次握手就是保证双手都有发送和接受的能力.那么最少三次才能验证完成 即----> 客户端发送---服务端收到----服务端发送-- 1.客户端发送 -- ...

  4. 网络 TCP三次握手,四次挥手详解

    三次握手,四次挥手可以说是炙手可热的面试题了,来看看它究竟长什么样子吧! 我们先把流程图贴上来 : 为什么这么复杂? 因为TCP是可靠性传输. 确认可靠传输的前提:  TCP连接管理机制 用TCP首部 ...

  5. TCP三次握手四次挥手

    看到一篇总结很好的TCP三次握手,学习一下,原文链接. 建立TCP需要三次握手才能建立,而断开连接则需要四次握手.整个过程如下图所示: 先来看看如何建立连接的. 首先Client端发送连接请求报文,S ...

  6. (转)TCP三次握手四次挥手

    转自:http://www.jellythink.com/archives/705 参考:http://blog.csdn.net/whuslei/article/details/6667471 [注 ...

  7. TCP三次握手/四次挥手详解

    一. TCP/IP协议族 TCP/IP是一个协议族,通常分不同层次进行开发,每个层次负责不同的通信功能.包含以下四个层次: 1. 链路层,也称作数据链路层或者网络接口层,通常包括操作系统中的设备驱动程 ...

  8. TCP 三次握手四次挥手, ack 报文的大小.tcp和udp的不同之处、tcp如何保证可靠的、tcp滑动窗口解释

    一.TCP三次握手和四次挥手,ACK报文的大小 首先连接需要三次握手,释放连接需要四次挥手 然后看一下连接的具体请求: [注意]中断连接端可以是Client端,也可以是Server端. [注意] 在T ...

  9. TCP三次握手四次挥手详解

    转载 http://www.cnblogs.com/zmlctt/p/3690998.html 相对于SOCKET开发者,TCP创建过程和链接折除过程是由TCP/IP协议栈自动创建的.因此开发者并不需 ...

随机推荐

  1. Educational Codeforces Round 65 (Rated for Div. 2)(ACD)B是交互题,不怎么会

    A. Telephone Number A telephone number is a sequence of exactly 11 digits, where the first digit is  ...

  2. 数据库系统第一章【绪论】(B站视频)

    目录 数据库系统第一章[绪论](B站视频) 一.绪论 数据库的四大基本概念 数据 数据库 数据库管理系统 主要功能 数据库系统 数据管理 我的理解 数据系统的特点 数据结构化 数据系统的共享性 数据独 ...

  3. Azure Blob (三)参数设置说明

    一,引言 上一篇将 Azure Blob 存储的时候,有使用到一个 .NET  Core Web 项目,通过代码的方式进行操作 Azure Blob 的数据,接着上一篇的内容,今天继续看一下代码,具体 ...

  4. 小程序开发-页面导航栏navigation-bar组件

    导航栏navigation-bar 页面导航条配置节点,用于指定导航栏的一些属性.只能是 page-meta 组件内的第一个节点,需要配合它一同使用. 通过这个节点可以获得类似于调用 wx.setNa ...

  5. 状压dp:luogu P2704 [NOI2001]炮兵阵地

    https://www.luogu.org/problemnew/show/P2704 知识点:1.滚动数组:取模实现 2.位运算优先级最低 顾是if(!(a&b))而不是if(!a& ...

  6. C013:颠倒显示三位数

    代码: #include "stdafx.h" int _tmain(int argc, _TCHAR* argv[]) { int original; do{ printf(&q ...

  7. String.format与搭配转化符的使用

    String的format语法搭配转化符,在格式化输出方面效果特别好,值得掌握. 例程: System.out.println("----C1---|----C2---|----C3---| ...

  8. linux 增加新用户无法使用sudo命令解决办法

    昨天一不小心把自己的系统搞崩了,也没有快照,没法进行还原操作,所以只能重装系统解决了,装完系统以后一切正常,当我新增了一个用户,使用sudo命令切换到root用户时,发现怎么都切换不过去,经过百度发现 ...

  9. Ubuntu 18.04 LTS 配置静态IPv6地址

    学校的IPv4地址限制了校内IP访问,在家连校内机器只能先连接学校的VPN,十分不方便.好在学校没有对IPv6地址做限制,因此我们可以给自己的机器配置一个静态IPv6地址来绕过这个限制. 本机系统使用 ...

  10. 图解冒泡排序及算法优化(Java实现)

    冒牌排序 基本思想 定义:冒泡排序的英文是bubblesort,它是一种基础的交换排序 原理:每次比较两个相邻的元素,将较大的元素交换至右端 (升序排序) 思路:相邻的元素两两比较,当一个元素大于右侧 ...