TCP 协议深度剖析

TCP/IP 协议族

TCP/IP(Transmission Control Protocol/Internet Protocol)传输控制协议/因特网互联协议,而 TCP/IP 协议族指的是 TCP/IP 的四层模型下的相关协议:

在这里插入图片描述

TCP/IP 也详细说明了各层的数据转换,在定义标准时也将实现过程规范了:

在这里插入图片描述

上图中用户发送数据在应用层开始逐层传递,传输层和网络层是 OS 内核会帮我们处理数据的封装和解析,在每一层都会添加传输相关的头信息用于数据识别和校验,最终通过网卡数据链路往外推数据,经过路由转发到目标,再从数据链路往上层解析数据到上层。

在网络传输过程中每一层的数据都有对应的信息单位:

  • 包:各层数据单位都可以说明为包

  • 消息:应用层的信息单位

  • 段:传输层的信息单位

  • 片:网络层的信息单位

  • 帧:专指数据链路层的信息单位

MAC、IP、端口及子网地址寻址问题

MAC

MAC 地址是网卡厂商用于标识网卡设备的编号,或者说是一个网络设备的相关标识

它在数据链路层在数据帧包发送传输时会将 MAC 地址带到数据帧包。一台计算机一般会有多个网络设备,网卡、wifi 等都是网络设备,所以查看系统可能会有多个 MAC 地址出现

在这里插入图片描述

网卡的主要功能有:

  • 数据的封装与解封装

  • 链路管理

  • 数据编码与译码

每一个网卡(网络设备)都有一个被称为 MAC 地址的独一无二的 48 位串行号,所以一般情况下 MAC 地址是唯一的

MAC 地址的长度为 48 位(6 个字节),通常表示为 12 个 16 进制数,如:00-16-EA-AE-3C-40 就是一个 MAC 地址,其中前 3 个字节 16 进制数 00-16-EA 代表网络硬件制造商的编号,它由 IEEE(电气与电子工程师协会)分配,而后 3 个字节 16 进制数 AE-3C-40 代表该制造商所制造的某个网络产品(如网卡)的序列号。

IP

IP 地址是一个 32 位的二进制数,通常被分割为 4 个 8 位二进制数(也就是 4 个字节),IP 是位于网络层,可以理解为 IP 是当前计算机使用的名称,主要用于路由寻址时使用

IP 地址通常用 “点分十进制” 的形式(a.b.c.d),其中 a、b、c、d 都是 0-255 之间的十进制整数。例如 IP 地址 100.4.5.6,实际上是 32 位二进制数 01100100.00000100.00000101.00000110。

端口

端口分围虚拟端口和物理端口。

  • 虚拟端口:指计算机内部或交换机路由器内的端口,不可见,是特指 TCP/IP 协议中的端口

  • 物理端口:也称为接口,是可见端口,计算机背板的 RJ45 网口等

端口类型也分为周知端口(Well Known Ports)、注册端口(Registered Ports)和动态/私有端口(Dynamic Ports / Private Ports)。

其中周知端口范围从 0-1023,它们紧密绑定于一些特定的服务。例如 80 端口分配给 www 服务,21 端口分配给 FTP 服务,23 端口分配给 Telnet 服务等。

很多人把 pid 和端口混淆,pid 是内核对进程分配的一个编号,用于系统内核对进程的识别;端口是进程对外的名字,即外面的数据要推到进程,需要先找到对外的端口假设为 8888,然后再根据这个端口 8888 找到 pid。这才是端口的实际意义

网络寻址过程

在这里插入图片描述

路由寻址过程:

  • 路由器会存储当前子网下的所有 IP-MAC,路由器维护着一个映射表也称为路由表,计算机的网络设备连接上路由时就会注册到路由表

  • 当计算机要发送数据包给另一台计算机时,数据包在链路当中会有 MAC 信息,路由在分发时可以让网络设备识别是否是自己的 MAC

  • 路由的分发直接以广播形式,所有注册到路由表中的子网网络设备会接收到数据包,但是网卡会识别数据包是否是当前 MAC 地址所需的信息,如果不是则会丢弃数据包

后续找到对应 MAC 地址的网络设备后,数据再进行解析后要给到哪个进程,就会通过端口例如 8888 再找到 pid 然后将数据给到对应进程。

因为路由是以广播的方式分发给已经注册到路由表的网络设备,所以一些网络嗅探抓包工具的工作原理例如 WireShark、Charles 等其实就是在路由分发时如果不是对应的 MAC 地址,不会丢弃数据包而是收集。

小结

简单总结下 MAC 地址、IP、端口和网络寻址。

  • MAC 地址是分配给每个网络设备的唯一编号,一台计算机可能会有多个网络设备,例如网卡、无线 wifi、蓝牙、NFC 等都属于网络设备

  • IP 可以简单理解为是用于标识机器的名称,这会在路由寻址时结合 MAC 地址注册到路由表,因为路由只通过 MAC 地址是不能实现寻址

  • pid 和端口不要混淆,pid 是内核对进程分配的一个编号,用于系统内核对进程的识别;端口是进程对外的名字,即外面的数据要给数据到进程,需要先找到对外的端口假设为 8888,然后再根据这个 8888 找到 pid

  • 网络寻址提到了路由寻址的过程,路由实际上没有寻址功能,而是将数据包通过广播的方式广播给每个注册到路由表的网络设备,数据包是对应 MAC 地址的网卡会接收数据,否则会丢弃数据

TCP 协议特性

TCP 协议是传输层协议,主要的作用就是做校验并保证数据完整性。TCP 协议是面向连接、可靠的、全双工的协议。

1、面向连接

面向连接需要实现端到端也就是一对一通信,相比 UDP 不需要面向连接的目的是为了一对多。

2、可靠性

TCP 可靠性是怎么保证的?

可以考虑一种场景:如果传递的数据过大比如有 1 GB,是否是一次性传输到位?

我们都清楚不是一次性就传输完,所以在处理过程中会对数据进行拆分处理,数据的拆分是在网络层进行分片操作,但是数据拆分后会有各种复杂网络状况出现,可能对方网络带宽拉满了,或者传输过程中丢包了。

所以 TCP 为了保证可靠性采用了两种方案:超时重传(RTO)和往返时延(RTT)

  • 超时重传:如果超过对应时间对数据进行重传,但是超时时间不能固定,超时时间不好界定

  • 往返时延:对超时重传方案的一种补充,一个数据包从当前端发送到对端,需要收到对端应答,这中间所损耗的时间会进行记录,每收到一个应答包则更新时间

3、全双工

全双工的意思是发送方和接收方都能做好数据接收的准备工作。它是 TCP 建立连接的前提,达成全双工也是三次握手的核心目的

TCP 三次握手

在说明 TCP 三次握手前需要简单罗列下讲解时需要了解的报文含义:

  • SYN:可以将它理解为是一个标志位,表示是否已经建立连接SYN=0 表示没有连接,SYN=1 表示已经我这边已经准备好 fd 做好了数据接收的准备

  • FIN:表示没有数据要发送

  • seq:如果是客户端发给服务端,seq 是用来给服务端识别是哪个客户端发送的报文,反之就是给客户端识别服务端。一般是一个随机的数据,并且 在网络处理中 seq 是一个累加的过程,比如客户端发送数据给服务端,seq 此时就会变动,seq 也能作为是否是有效连接(请求连接没有过期或超时)判断的依据

  • ACK:应答报文,表示已经知道了对方刚才发的报文

  • ack:告诉对方我确实知道了是哪个客户端/服务端告知的我,所以 ack 是在对方的 seq 基础上累加数值

下图是 TCP 三次握手图解:

在这里插入图片描述

  • 第一次握手:客户端主动准备好了 fd 后,发送 SYN=1 给服务端,表示客户端已经做好了数据接收的准备,并且报文 seq=2222 让服务端在后续和客户端连接时能识别是指定的客户端

  • 第二次握手:服务端在接受到客户端发的 SYN=1,seq=2222 报文后,也开始准备 fd,然后发送 SYN=1 表示也做好了数据接收准备,报文 seq=6666 让客户端在后续和服务端连接时能识别指定服务端;ACK=1 表示服务端已经知道客户端刚才发的 SYN=1,seq=2222,知道客户端有 fd 数据接收能力了,同时为了验证应答,服务端把客户端的 seq=2222 提出来 +1 作为 ack=2223 一起返回给客户端做验证

  • 第三次握手:客户端在收到服务端的应答后,还需要再发送一次 ACK=1,ack=6667 告知服务端已经知道你的应答并且把你的 seq=6666 提出来 +1 作为 ack=6667 一起返回让你做校验

三次握手的核心目的在于建立连接,而建立连接的前提是要求全双工,全双工的意思是发送方和接收方都能做好数据接收的准备工作

在了解了 TCP 三次握手的流程后,就可以回答 TCP 常见的问题。

为什么要三次握手,而不是两次?

[1] 为了防止无效连接

三次握手时,在网络拥堵等情况下,第一次握手的 SYN 包迟迟没能发送到服务端,那么客户端会连续发送 SYN 建立连接的报文,就可能会出现旧的 SYN 报文比最新的 SYN 报文早到达服务端。

服务端收到 SYN 报文后会应答一个 SYN+ACK 报文给客户端;假设是两次握手,服务端就不能判断是否是旧的还是最新的 SYN 报文请求的建立连接,客户端有请求连接的报文都响应,但客户端并不需要,导致错误。如下图:

在这里插入图片描述

所以如果是三次握手,客户端收到服务端的响应报文后,就可以根据自身上下文判断这是一个历史连接(seq 序列号过期或超时),客户端就会发送 RST 报文给服务端,中止这一次连接。

在这里插入图片描述

[2] 避免资源浪费

当客户端的 SYN 请求连接在网络中阻塞,客户端没有服务端收到 ACK 报文,就会重新发送 SYN。如果只有两次握手,服务端不清楚客户端是否收到了自己发送的建立连接的 ACK 确认信号,所以 每收到一个 SYN 就只能先主动建立一个连接创建 fd,就会出现建立多个冗余无效的连接,造成资源浪费

在这里插入图片描述

TCP 四次挥手

在这里插入图片描述

  • 第一次挥手:客户端先将 fd close,但此时并没有释放(因为此时服务端可能还在发数据给客户端),而是发送一个报文给服务端 FIN=1, seq=98765 告知已经没有数据发送给你了

  • 第二次挥手:服务端接收到客户端的消息后,服务端会应答 ACK=1, ack=98766 给客户端,表示已经收到了你的 FIN 报文,把你的 seq 提出来 +1 也一同发给你做校验

  • 第三次挥手:等到服务端把发给客户端的数据都发完了,服务端主动再发一次消息 FIN=1, seq=12345,表示我这边也没东西给你了,客户端此时处于 TIME_WAITING 状态

  • 第四次挥手:等客户端响应发回 ACK=1,seq=12346,服务端就处于 CLOSED 状态,此时服务端释放 fd 资源,客户端也会在 2 MSL 时间后再释放 fd 资源

按正常来讲,客户端没有数据发给服务端,服务端也没有数据发给客户端,客户端的 fd 是可以销毁释放的,但实际上客户端的 fd 是做了延迟的释放,官方定义为 2 MSL

MSL 报文网络最长存活时间,官方定义为 2 分钟,但是一般 OS 实现定义为 30s,TIME_WAITING 一般时间为 1-4 分钟

1、客户端为什么要有 TIME_WAITING 状态延迟释放 fd?

在第四次挥手客户端处在 TIME_WAITING 状态要响应服务端,服务端这条消息是有可能因为网络原因没有收到,服务端是有可能让你将这条消息重传。所以如果此时客户端在收到第三次挥手后不是处在 TIME_WAITING 状态延迟将 fd 释放,而是直接进入 CLOSED 状态释放了 fd,那么重传就不能实现,服务端也就不会释放 fd

在这里插入图片描述

2、为什么要四次挥手?

实际上四次挥手并不是绝对的,在常规的抓包中存在一种现象:ACK=1,ack=98766 和 FIN=1,seq=12345 是在一条报文发过来的。四次挥手是 TCP 协议的标准,但实际业务可以不是四次,也可以是三次挥手

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值