1

什么TCP

https://www.processon.com/diagraming/5e154137e4b0bcfb73390288

互联网由一整套协议构成。TCP 只是其中的一层,有着自己的分工。TCP 是以太网协议和 IP 协议的上层协议,也是应用层协议的下层协议。

image

IP层是「不可靠」的,它不保证网络包的交付、不保证网络包的按序交付、也不保证网络包中的数据的完整性。

如果需要保障网络数据包的可靠性,那么就需要由上层(传输层)的 TCP 协议来负责。

因为 TCP 是一个工作在传输层可靠数据传输的服务,它能确保接收端接收的网络包是无损坏、无间隔、非冗余和按序的。

TCP 是面向连接的、可靠的、基于字节流的传输层通信协议。

面向连接:一定是「一对一」才能连接,不能像 UDP 协议 可以一个主机同时向多个主机发送消息,也就是一对多是无法做到的;

可靠的:无论的网络链路中出现了怎样的链路变化,TCP 都可以保证一个报文一定能够到达接收端;

字节流:消息是「没有边界」的,所以无论我们消息有多大都可以进行传输。并且消息是「有序的」,当「前一个」消息没有收到的时候,即使它先收到了后面的字节已经收到,那么也不能扔给应用层去处理,同时对「重复」的报文会自动丢弃。

TCP数据包的组成

image

序列号:在建立连接时由计算机生成的随机数作为其初始值,通过 SYN 包传给接收端主机,每发送一次数据,就「累加」一次该「数据字节数」的大小。用来解决网络包乱序问题。

确认应答号:指下一次「期望」收到的数据的序列号,发送端收到这个确认应答以后可以认为在这个序号以前的数据都已经被正常接收。用来解决不丢包的问题。

控制位:

ACK:该位为 1 时,「确认应答」的字段变为有效,TCP 规定除了最初建立连接时的 SYN 包之外该位必须设置为 1 。

RST:该位为 1 时,表示 TCP 连接中出现异常必须强制断开连接。

SYC:该位为 1 时,表示希望建立连,并在其「序列号」的字段进行序列号初始值的设定。

FIN:该位为 1 时,表示今后不会再有数据发送,希望断开连接。当通信结束希望断开连接时,通信双方的主机之间就可以相互交换 FIN 位置为 1 的 TCP 段。

TCP 四元组可以唯一的确定一个连接,四元组包括如下:

源地址,源端口,目的地址,目的端口

image

Wireshark抓包工具

Wireshark 就是最常用的网络抓包和分析工具,更是分析网络性能必不可少的利器。它除了可以抓包外,还提供了可视化分析网络包的图形页面。

安装

打开下载好的软件包, 将Wireshark.app 拖动到Applications 中并双击Install ChmodBPF.pkg, 只有安装了这个, 才能捕获数据包

image

使用

以访问www.baidu.com为例

ping www.baidu.com 查看IP

image

curl www.baidu.com

(只想查看一下三资握手, 直接打开页面的话会有一大堆的请求,影响查看, 所以采用curl的方式)

在Wireshark通过filter里面监听百度的ip地址,得到TCP三次握手四次挥手的信息:

image

TCP三次握手四次挥手

HTTP 是基于 TCP 协议进行传输的,那么:

  • 最开始的 3 个包就是 TCP 三次握手建立连接的包
  • 中间是 HTTP 请求和响应的包
  • 而最后的 3 个包则是 TCP 断开连接的挥手包

Wireshark 可以用时序图的方式显示数据包交互的过程,从菜单栏中,点击 统计 (Statistics) -> 流量图 (Flow Graph),然后,在弹出的界面中的「流量类型」选择 「TCP Flows」,整个过程中 TCP 流的执行过程:

image

这里Seq=0,是因为 Wireshark 工具帮我们做了优化,它默认显示的是序列号 seq 是相对值,而不是真实值。客户端和服务端的序列号实际上是不同的,序列号是一个随机值。

TCP三次握手

  • 一开始,客户端和服务端都处于 CLOSED 状态。先是服务端主动监听某个端口,处于 LISTEN 状态
  • 客户端会随机初始化序号(client\_isn),将此序号置于 TCP 首部的「序号」字段中,同时把 SYN 标志位置为 1 ,表示 SYN 报文。接着把第一个 SYN 报文发送给服务端,表示向服务端发起连接,该报文不包含应用层数据,之后客户端处于 SYN-SENT 状态。
  • 服务端收到客户端的 SYN 报文后,首先服务端也随机初始化自己的序号(server\_isn),将此序号填入 TCP 首部的「序号」字段中,其次把 TCP 首部的「确认应答号」字段填入 client\_isn + 1, 接着把 SYN 和 ACK 标志位置为 1。最后把该报文发给客户端,该报文也不包含应用层数据,之后服务端处于 SYN-RCVD 状态。
  • 客户端收到服务端报文后,还要向服务端回应最后一个应答报文,首先该应答报文 TCP 首部 ACK 标志位置为 1 ,其次「确认应答号」字段填入 server\_isn + 1 ,最后把报文发送给服务端,这次报文可以携带客户到服务器的数据,之后客户端处于 ESTABLISHED 状态。服务器收到客户端的应答报文后,也进入 ESTABLISHED 状态。

一旦完成三次握手,双方都处于 ESTABLISHED 状态,此致连接就已建立完成,客户端和服务端就可以相互发送数据了。

*第三次握手是可以携带数据的,前两次握手是不可以携带数据的,这也是面试常问的题。*

为什么是三次握手

为什么三次握手才可以初始化Socket、序列号和窗口大小并建立 TCP 连接。**

接下来以三个方面分析三次握手的原因:

  • 三次握手才可以阻止重复历史连接的初始化(主要原因)

客户端连续发送多次 SYN 建立连接的报文,在网络拥堵等情况下:
一个「旧 SVN 报文」比「最新的 SYN 」 报文早到达了服务端;那么此时服务端就会回一个 SYN + ACK 报文给客户端;客户端收到后可以根据自身的上下文,判断这是一个历史连接(序列号过期或超时),那么客户端就会发送 RST 报文给服务端,表示中止这一次连接。
如果是两次握手连接,就不能判断当前连接是否是历史连接,三次握手则可以在客户端(发送方)准备发送第三次报文时,客户端因有足够的上下文来判断当前连接是否是历史连接。

  • 三次握手才可以同步双方的初始序列号

TCP 协议的通信双方, 都必须维护一个「序列号」, 序列号是可靠传输的一个关键因素。它的作用:接收方可以去除重复的数据;接收方可以根据数据包的序列号按序接收;可以标识发送出去的数据包中, 哪些是已经被对方收到的;
当客户端发送携带「初始序列号」的 SYN 报文的时候,需要服务端回一个 ACK 应答报文,表示客户端的 SVN 报文已被服务端成功接收,那当服务端发送「初始序列号」给客户端的时候,依然也要得到客户端的应答回应,这样一来一回,才能确保双方的初始序列号能被可靠的同步。**

  • 三次握手才可以避免资源浪费

TCP四次挥手

  • 客户端打算关闭连接,此时会发送一个 TCP 首部 FIN 标志位被置为 1 的报文,也即 FIN 报文,之后客户端进入 FIN\_WAIT\_1 状态。
  • 服务端收到该报文后,就向客户端发送 ACK 应答报文,接着服务端进入 CLOSED\_WAIT 状态。
  • 客户端收到服务端的 ACK 应答报文后,之后进入 FIN\_WAIT\_2 状态。
  • 等待服务端处理完数据后,也向客户端发送 FIN 报文,之后服务端进入 LAST\_ACK 状态。
  • 客户端收到服务端的 FIN 报文后,回一个 ACK 应答报文,之后进入 TIME\_WAIT 状态
  • 服务器收到了 ACK 应答报文后,就进入了 CLOSE 状态,至此服务端已经完成连接的关闭。
  • 客户端在经过 2MSL 一段时间后,自动进入 CLOSE 状态,至此客户端也完成连接的关闭。

主动关闭连接的,才有 TIME\_WAIT 状态。**

从上面过程可知,服务端通常需要等待完成数据的发送和处理,所以服务端的 ACK 和 FIN 一般都会分开发送,从而比三次握手导致多了一次。

存在TIME\_WAIT的两个原因:1。终止可靠的TCP全双工连接2.允许旧的重复数据包在网络中消失

TIME\_WAIT 等待的时间是 2MSL**

MSL 是 Maximum Segment Lifetime,报文最大生存时间,它是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。因为 TCP 报文基于是 IP 协议的,而 IP 头中有一个 TTL 字段,是 IP 数据报可以经过的最大路由数,每经过一个处理他的路由器此值就减 1,当此值为 0 则数据报将被丢弃,同时发送 ICMP 报文通知源主机。

TIME\_WAIT 等待 2 倍的 MSL,比较合理的解释是: 网络中可能存在来自发送方的数据包,当这些发送方的数据包被接收方处理后又会向对方发送响应,所以一来一回需要等待 2 倍的时间

TCP 流量控制

TCP 为了防止发送方无脑的发送数据,导致接收方缓冲区被填满,所以就有了滑动窗口的机制,它可利用接收方的接收窗口来控制发送方要发送的数据量,也就是流量控制。

接收窗口是由接收方指定的值,存储在 TCP 头部中,它可以告诉发送方自己的 TCP 缓冲空间区大小,这个缓冲区是给应用程序读取数据的空间:

  • 如果应用程序读取了缓冲区的数据,那么缓冲空间区的就会把被读取的数据移除
  • 如果应用程序没有读取数据,则数据会一直滞留在缓冲区。

接收窗口的大小,是在 TCP 三次握手中协商好的,后续数据传输时,接收方发送确认应答 ACK 报文时,会携带当前的接收窗口的大小,以此来告知发送方。

TCP 和 UDP 区别

1. 连接**

TCP 是面向连接的传输层协议,传输数据前先要建立连接。UDP 是不需要连接,即刻传输数据。

2. 服务对象**

TCP 是一对一的两点服务,即一条连接只有两个端点。UDP 支持一对一、一对多、多对多的交互通信

3. 可靠性**

TCP 是可靠交付数据的,数据可以无差错、不丢失、不重复、按需到达。UDP 是尽最大努力交付,不保证可靠交付数据。

4. 拥塞控制、流量控制**

TCP 有拥塞控制和流量控制机制,保证数据传输的安全性。UDP 则没有,即使网络非常拥堵了,也不会影响 UDP 的发送速率。

5. 首部开销**

TCP 首部长度较长,会有一定的开销,首部在没有使用「选项」字段时是 20 个字节,如果使用了「选项」字段则会变长的。UDP 首部只有 8 个字节,并且是固定不变的,开销较小。

TCP 和 UDP 应用场景:**

由于 TCP 是面向连接,能保证数据的可靠性交付,因此经常用于:

FTP 文件传输HTTP / HTTPS

由于 UDP 面向无连接,它可以随时发送数据,再加上UDP本身的处理既简单又高效,因此经常用于:

包总量较少的通信,如 DNS 、SNMP 等视频、音频等多媒体通信广播通信


花花呀
375 声望23 粉丝

学无止境 做有灵魂的程序员