TCP概述与报文格式
TCP协议的知识很多,开发日常工作中已较少直接涉及,但仍然有学习的价值,因为这些知识中体现出一种软件工程智慧凝聚与客观最佳实践,有助于类似场景下的借鉴与灵活运用,因此结合最近的学习进行一次总结。
概述
OSI/RM体系结构将整个网络通信的功能划分为七个层次,由低到高分别是物理层、数据链路层、网络层、传输层、会话层、表示层、应用层,TCP协议位于其中第四层-传输层。OSI/RM七个层次的划分最初是作为标准存在的,但实践过程却并非严格按照标准进行实现,因此出现了另外一种体系结构-TPC/IP协议体系结构,其按功能划分为四层,由低到高分别是网络访问层、网际互联层、传输层、应用层。两种方案都是为了解决网络通信中的相同或相似问题,因此四层与七层模型存在一个对应关系:
由于合理性或历史原因等,整个网络体系结构实际发展是依照四层模型进行的,因此四层模型是当前的实际标准,而四层模型中把物理层和数据链路层合并为网络访问层,对于学习与实现均不合理,因此当前标准与实现的最佳的平衡点是TCP/IP五层体系结构。
分层本身是一种软件工程界解决问题的一种方式,五层模型中每一层的目标有所不同,重点关注内容也有差异:
- 应用层,各类应用根据特征扩展使用,具体协议有:HTTP、Websocket、SSL、SMTP、gRPC等
- 传输层,提供端到端的可靠传输,应用通信的逻辑通道,具体协议有:TCP、UDP等
- 网际互联层,寻址与路由选择,确定广域网通信的路径,具体协议有:IP、ARP、ICMP等
- 数据链路层,相邻节点的点到点可靠传输,基于MAC地址通信,数据传输的逻辑通道
- 物理层,二进制的比特流传输,无线电、网线等物理设备的收发,数据传输的物理通道
不同层的加深理解
数据链路层
数据链路层的作用是建立局域网数据传输通道,通道所依赖的连接本身是永久建立的,如连接好的两个设备A-B直连通信或者三个设备A-S-B(其中S是二层交换机)转发通信,这里的A-B逻辑通信通道可以表示为“A.MAC地址<=>B.MAC地址”。而如果是广域网中两台设备A’-B’进行通信,这时数据链路层的逻辑通道“A’.MAC地址<=>B’.MAC地址”需要依赖更上一层的网际互联层(IP)决定,整个逻辑链路中也会出现其他设备的MAC地址,即处于广域网中的A’-B’无法仅依靠MAC地址完成通信。
数据链路层相关的几个重要设备:集线器(物理层)、网桥、二层交换机:
- 集线器,早期设备,N个端口其中某一个端口输入数据,剩余N-1个端口会输出相同数据
- 网桥,较早期设备,通常配合集线器将两个物理网络连通,如两个网络N(设备A、B、C)、M(设备X、Y、Z)物理上没有联通,因此设备A无法与设备X通信,如果我们用网桥将N与M连通,则A与Z可以进行通信。物理网桥现今很少接触了,但经常可见到虚拟网桥如docker0,故了解此设备的用途有助于理解Docker网络模型
- 二层交换机,N个端口其中某一个端口输入数据,会根据MAC地址找到匹配的端口输出,如果没有找到匹配端口则输出到剩余N-1个端口上
网际互联层
前面知道广域网中无法使用设备的MAC地址进行通信,网际互联层则是为了解决此问题,提供广域网中的数据传输逻辑通道,但更关注的是逻辑而非通道,解决的是网络与网络之间的互联问题,其中核心是寻址路由。
寻址路由,址是唯一定位和识别,如同每个人的身份证号码与人绑定,根据身份证号码可以找人,在网际互联层中这个身份证号即是IP地址,路由是根据IP地址从出发端找到一条数据合理可达的逻辑路线
需要提到的是每一个三层数据包都无法凭空投送到目标IP设备,需要转到数据链路层通过MAC地址进行传递,所以这里有一个IP地址与MAC地址转换问题依赖ARP协议完成:“通过广播发送包含目标IP的包给局域往中所有设备,如果某设备发现自己IP与包中目标IP相同,则回包表明自己的MAC地址是目标IP所对应的”,有点像大学老师不认识每个学生通过点名判断学生是否到课,因而可能出现冒名顶替。
这一层还有一个重要知识点是NAT,NAT服务运行在位于内、外网之间的路由设备上,在内、外网用户之间通信时对数据包中的地址进行转换,其转换原理如下图所示:
PS:linux下iptables可以很方便使用NAT能力,类似“三层代理”,代理主机充当路由器身份
传输层
网际互联层解决了主机(IP)与主机(IP)间通信链路问题,传输层则是为应用层提供主机与主机间的端到端通信方案,且它与网际互联层关注的问题有所差异,尤其是TCP协议解决了的各种复杂问题。
用一个包裹派送的比喻来说明传输层相比较网际互联层多提供了什么:
- 网际互联层,相当于包裹可以精准到你所在的小区,但没有定义应该如何到你手上
- 传输层,你所在的小区有快递柜,包裹会被分别放到快递柜(临时租用),然后你从快递柜中取包裹
而TCP协议作为传输层的最佳实践,用快递员派送包裹举例解决了如下可能问题:
- 包裹内的物件不应该损坏(差错校检)
- 不应该收到非自己的包裹(可靠连接,端对端)
- 快递员派送包裹前应该提前跟你约时间(可靠连接)
- 包裹需要亲自送到你手上(ACK)
- 你不在家,没亲自送到你手上的包裹,应该继续派送到你手上(丢包重传)
- 包裹丢失时,你能察觉(包序号、ACK、SACK)
- 包裹多的时候,快递员尽量一起送给你(TCP程序发送缓存区与发送时机)
- 包裹急的时候,快递员尽量最快速度送给你(TCP程序发送缓存区与发送时机)
- 快递员会依照你需要的节奏,恰当的给你派送包裹(流量控制)
- 快递员不会因为其他人要派送的包裹太多而没法派送你的(拥塞避免)
TCP数据包格式
TCP数据包或称为数据段的完整格式如下:
- 源端口与目的端口
TPC提供端到端的可靠传输,源端口与目的端口即端概念的具体表现,16位能表达的最大端口是65535
- 序号(Sequance Number)
指TCP数据包中净荷部分(不包含数据包首部)的第一个字节编号,若其中一个数据包序号n,净荷长度l,则其随后一个数据包序号为:n + l
- 确认号(Acknowledgment Number)
期待接受对方下一个数据包中净荷部分的第一个字节序号
- 数据偏移
指数据包中净荷部分起始处距离TCP数据包起始处的偏移量,用来确认数据包首部长度,此部分长度为4限制了TCP数据包首部的最大长度为60字节((2 ^ 4 - 1) x 32位 / 8)
- ACK
Acknowledgment控制位,指示TCP数据包中的确认号字段是否有效,常说的“ACK包”即此控制位置位为1的包,ACK包也可携带净荷发送数据
- PSH
Push控制位,指示是否需要立即把收到的数据提交给应用进程,在某些特殊场景有用
- RST
Reset控制位,用于重置、释放一个已经混乱的传输连接,TCP处理程序在自己认为的异常时刻发送RST包
- SYN
Synchronization控制位,用于传输连接建立时同步传输连接序号,SYN=1时,表示这是一个连接请求或连接确认报文
- FIN
Final控制位,用于释放一个传输连接,Fin=1时,表示数据已传输完成,发送端没有数据要传输了,接收端此时仍可接收在途数据包,直到确认接收完成再回ACK
- 窗口大小
指示发送此TCP数据包的主机上用于存储传入数据段的窗口大小,接收端用于控制发送端最大在途TCP数据包数量的手段
- 数据
数据也称净荷,应用层的应用程序提交到TCP处理程序中的数据
学习TCP数据包格式的作用在于理解这种设计方式,倒不是要严格记住每个bit & bytes作用,后续如果接触其他应用层协议,其通信数据包若按照二进制分帧也会与TCP这种形式大同小异。