文章目录
- TCP协议
- TCP数据段格式
- TCP确认应答机制
- TCP流量控制
TCP协议
TCP协议(Transmission Control Protocol , 传输控制协议) 是互联网协议套件中的核心协议之一;
主要用于确保数据在网络上的可靠传输,其具有以下特点:
-
面向连接
在数据传输前,TCP需要在通信双方之间建立一个连接,这个连接需要通过三次握手来完成从而保证两端的通信准备就绪;
-
可靠传输
TCP提供可靠的数据传输服务,确保数据包能够按照顺序且无差错的送达目标;
其中包括错误检测,重传机制,确认应答等手段来保证数据的完整性和正确传输;
-
流量控制
TCP实现流量控制,通过滑动窗口机制确保发送方不会以超过接收方处理能力的速度发送数据从而避免网络拥塞;
-
拥塞控制
TCP通过各种算法来检测和应对网络拥塞,调整发送速度,优化网络资源使用;
-
数据序列化和重组
发送方将数据流分割成多个数据段发送,在接收方将这些数据段按照顺序重新组装成完整的数据流以保障数据顺序的正确;
-
全双工
TCP支持全双工通信,即通信双方可以同时进行数据的发送和接收以提高通信效率;
-
端口和多路复用
TCP使用端口号来标示不同的应用程序,并通过多路复用技术支持多个应用程序在同一物理链路上进行传输;
TCP是一种传输控制协议,其中该协议最主要的特点在于 “控制” ,与UDP协议不同,TCP协议具有两个缓冲区,即输入缓冲区与输出缓冲区;
当执行流在使用TCP协议进行数据发送时所调用的sendto
本质上是一个拷贝函数,这个函数将数据由应用层协议缓冲区拷贝至传输层协议的缓冲区,当TCP协议识别到缓冲区存在数据时将自行判断数据是否发送以及发送,同时TCP协议也将自行解决如丢包,数据不完整等问题,故被称为控制协议;
TCP的缓冲区是一种内存级缓冲区,与用户或者应用层在数据整合时或者接收传输层上来的数据的缓冲区是不同的;
同时TCP也具有接受缓冲区,这个接收缓冲区和UDP的接收缓冲区同理,在此不做赘述;
TCP数据段格式
TCP数据段格式包含以下内容:
-
16位源端口号
发送方的端口号;
-
16位目标端口号
接收方的端口号;
-
32位序号
标示该段中数据的第一个字节在整个数据流的位置;
-
32位确认序号
用于确认接收到的数据,是期望接收下一个字节的序号;
-
4位首部长度
自描述字段,指定TCP头部的长度,单位是32位(
4Byte
); -
6位保留字段
保留供将来使用,目前设置为0;
-
控制标志
包括
URG
,ACK
,PSH
,RST
,SYN
,FIN
等,用于控制数据流和连接管理; -
16位窗口大小
表示接收方当前可以接收的数据量,用于流量控制;
-
16位校验和
检测数据段头部和数据是否有错误;
-
16位紧急指针
指示紧急数据的末尾,用于加快处理紧急数据;
-
选项
可选字段,例如最大报文段长度(MSS),时间戳等;
-
数据
实际传输的数据部分;
当接收方接收到一个TCP报文后需要对报文进行报头和有效载荷的分离以及将分离后的数据交付给上层;
对于TCP协议的报头而言其也是以定长报头从而更好的进行报头和有效载荷的分离;
通常情况下TCP协议的报头定长为20byte
,但TCP报文与UDP报文不同,UDP报文的格式为定长报头后紧跟正文数据,而TCP协议在报头与正文数据中夹杂着一层 “选项” ,TCP对报头与有效载荷的分离工作变成了:
- TCP如何将报头(标准报头与选项)和有效载荷进行分离?
虽然TCP的报文中出现了选项字段,但是在TCP的报头中存在一个 “4位首部长度” 的字段用于更好的将报头与有效载荷进行分离;
“4位首部长度” 记录的是TCP标准报头与选项的总大小,其有四位,取值范围即为 [0-15]
,其单位为32bit
(4字节),即整个TCP报头的大小为0~60byte
;
当接收方接收到了一个TCP报文后将会对应的读取其首部长度,通过首部长度来计算出TCP报头的总大小,通过总大小减去定长报头(TCP标准报头)的大小后剩下的则为选项所占大小,计算完报头总体大小后即可对报头与有效载荷进行分离;
当报头与有效载荷分离后需要将报文交付给上层,在TCP报头中存在 “16位目标端口号” 字段,一个端口号只能被一个进程所绑定,所以TCP协议可以精准的将有效载荷部分通过该字段精准交付给上层对应的进程;
与UDP相同,TCP的报头也是以结构化的形式所存在;
同时,无论是请求还是响应,无论数据是否完整,使用TCP协议发送与接收的报文都是一个完整的TCP报文,即该TCP数据段必须包含完整的TCP报头;
TCP确认应答机制
在使用TCP协议进行网络通信时,当客户端发送给服务端发送一次字节流时,服务端必须对该字节流进行响应,否则客户端无法知道最近一次对服务端发送的字节流是否有到达;
同样的,当服务端对客户端发送一段数据段后,对应的客户端也需要对该次字节流进行一次应答;
通过确认应答机制可以保证发送方向接收方数据发送时的可靠性,这个可靠性是相互的,即在每次会话当中必然存在一个发送方与一个接收方(无论是客户端还是服务器);
同时这里的发送方所发送的数据还是接收方所返回的应答都是一个TCP数据段,无论其是否包含数据,该数据段都是一个完整的TCP报文(必定携带TCP报头);
对于应用层协议而言,分为主从概念,即存在客户端也存在服务端,而传输层中的协议,无论是发送方还是接收方其低位是对等的,在传输层进行的网络通信任何一方都会成为发送方同时也会扮演接收方的角色;
而在确认应答机制中可能会存在一个 鸡生蛋蛋生鸡 的问题,即A端向B端发送字节流,B端回复A端字节流使A端明白刚刚所发的字节流已经被接收,那么B端又如何证明该回复的字节流被A端所接收,A端是否需要对该回复字节流再次进行一次应答?
无论通信双方如何进行通信,在最后一条应答字节流后是没有应答的,这也意味着TCP协议尽管尽力提供可靠的通信连接,但也无法保证100%
的可靠;
实际上TCP协议并不保证全局通信中的可靠性,只有当一条字节流发送给对端,并且对端对该字节流进行了应答才能保证最新的字节流(应答字节流),之前的字节流是可靠的;
而实际TCP协议在设计过程中也考虑到了这一点,所以在实际通信过程中, 发送方无需对应答再作应答 ;
假设存在两个端分别为A端与B端,每个端既是发送方也是接收方,那么通信过程中保证可靠传输将会有以下两种情况:
- A端向B端发送数据,B端应答,保证A端到B端数据传输可靠性
- B端向A端发送数据,A端应答,保证B端到A端数据传输可靠性
而实际上不考虑第一条与最后一条的字节流通信,实际上在中间过程中的字节流传输既可以被看作是数据传输,也可以看作是应答;
只有当一端向另一端发送字节流并且另一端为该字节流进行应答了该端才会知道对端已经接收到了字节流,否则则无法确认该字节流是否被传达,为了保证数据传输的可靠性,TCP协议制定了一个定时任务,即当一条字节流被发送出去后一段时间没有接收到应答则会判定为数据丢失,将重新发送该数据段,即 “超时重传” ;
在上述的网络通信过程中采用的是串行的方式,即双端在接收到对方的应答再发送下一条字节流,而实际上串行的网络通信的过程与效率十分低下;
通常情况下TCP协议所采用的通信方式是一端向另一端发送字节流时为多条字节流并行发送,当对端接收到对应的字节流后只需要对每条字节流进行应答即可;
假设存在两端,A端与B端,当A端向B端以并行的方式发送多条字节流,B端对A端进行逐条字节流的应答,但在网络通信过程中没有百分百的可靠传输,即并行发送的多条字节流可能因为网络拥塞等情况将会出现多条字节流乱序的情况,即 “数据包乱序” ,这种情况会导致数据段由传输层交付给应用层时出现解析出乱序的数据报从而导致无法正确识别对应的正确数据,而数据包乱序本质上就是不可靠的一种体现;
为了避免对端因为数据段乱序导致无法正确识别整理报文,TCP协议制定了一个这样的规则,通过报头中的某个字段对多个数据段进行排序,即 “序号与确认序号” ,通过序号来保证数据的 “按序到达” ;
-
32位序号
序号是用于标示数据流中每个字节的位置,具体来说,TCP将数据视为一个连续的字节流,每个字节都有一个唯一的序列号;
序列号用于标示每个字节的位置确保数据按顺序传输和重组;
在TCP建立连接时双方都将随机选择一个序列号,通常情况下在建立连接的三次握手中会协商这些数据,随机选择是为了保证安全性;
对于后续的序列号将会根据数据段的数量对序列号进行递增,如果初始序列号是
1000
,发送了500
字节的数据,下一字节的序列号将是1500
,这也将根据窗口大小动态进行调整;同时为了保证TCP报文不会因为序号而超过报头的固定长度,在一定长度后序号将会进行回滚,通常情况下当序号到达
4,294,967,295
,即32位满,对应序列号将会回滚为0
,由0
开始计算,除该情况外,TCP报头的序号是伴随整个连接的数据发送递增的(对单独一端而言); -
32位确认序号
确认序号既表示告诉对端在该确认序号之前的所有字节流已经被进行接收的应答,也是期望对端下一序列号的开始位置,通常为向后偏移一个字节;
由于序列号的实际范围为 “序列号 + 报文有效载荷长度 - 1” , 对于确认序号而言,其所填充的数据是所接收的数据流的 “序列号 + 报文有效载荷长度” ;
这是一种协议上的约定,在TCP网络通信过程中可能会因为网络拥塞或是其他问题导致的数据丢失问题,但依靠这种约定对端可以明确知道在该确认序号前的所有序号的数据流已经被接收;
即一个确认序号可以代表多条数据流的应答;
一端在对另一端发送数据流时本质上也是对对端上一所发数据流的应答,但是在应答当中可能出现不存在有效载荷的情况,即没有有效正文数据,此时对应的确认应答即能成为对对端上一所发数据的应答;
序号和确认序号可能同时存在,尤其是在双向通信过程中;
同时因为确认序号的存在,TCP协议在进行网络通信过程中允许少部分的应答丢失;
TCP流量控制
TCP协议是一种提供可靠传输服务的协议,其中可靠传输包含了防止丢包的问题;
对于丢包的问题有很多,包括网络传输过程中丢包,发送方的发送速度大于接收方处理TCP报文的处理能力导致的丢包,但无论是哪种丢包TCP协议都能通过重传,超时重传,快速重传等策略为TCP的数据传输提供可靠性;
但对于发送端与接收方处理能力不匹配的情况,如果出现大量的丢包情况则可能降低双方的效率,尤其是对于发送方而言,接收方无法快速处理来自发送方所发来的TCP数据段从而导致接收缓冲区溢出,则每次新的从发送方发来的TCP数据段都将可能被丢弃,导致发送方为了保持数据传输的可靠性而不停重传,大大降低了发送端的效率;
在这种情况下,发送方无法确认数据段为什么会丢包,但以发送方的视角而言该次丢包就是不可靠的,所以为保证数据传输可靠性发送方将不停重发,直至接收方将接收缓冲区中的数据段处理了一些以有足够的空间来容纳本次来自发送端的数据段;
而TCP协议是一种保证可靠性的传输方式,其自身使用对应的策略来应对这种问题的发生从而避免因为双方处理能力不兼容从而导致大面积丢包情况;
通常采用匹配双方处理能力从而使得接收方不会因为发送方所发送的数据段过多导致就接收缓冲区溢出从而引起的大面积丢包,这种策略被称为流量控制;
对发送方而言,发送速度需要由对方的接收缓冲区中所剩余的空间大小来决定,同时TCP协议是基于确认应答机制的;
在TCP报头中存在字段 “16位窗口大小” , 该字段就是标明本端中的窗口大小,即告诉对端本端所期望的下次接收数据的大小,这个窗口大小是一个约定值(约定下次所发的数据不超过该大小),当一端向另一段返回对应的数据段时报头中将携带这一字段,对端再次发送数据段时只需发送不超过该窗口大小的数据量即可;
窗口大小是通信过程中一个动态的字段,本端将会根据自己的处理能力以及当前接收缓冲区的剩余空间来重新规划窗口大小,即 “滑动窗口” ;
通常在一次连接当中都将使用 “慢启动” 的方式来设置窗口大小从而匹配双端的处理速度;
-
慢启动
从一个较小的窗口大小开始传输数据,并逐步增大窗口大小,以此适应网络的实际容量;