TCP协议详解


前言


提示:以下是本篇文章正文内容

一、TCP协议概述

1.协议特点

(1)TCP是面向连接(虚连接)的传输层协议

通信双方在发送数据之前必须建立连接,连接状态只在连接的两端中维护,在沿途节点中并不维护状态

TCP连接包括:两台主机上的缓存、连接状态变量、socket等

(2)每条TCP连接只能有两个端点,每条TCP连接只能是点对点的

这里TCP连接的端点不是主机,不是主机的IP,也不是应用进程和运输层的协议端口,TCP连接的端口是套接字(Socket) 【套接字 =(IP地址:端口号)】

每一条TCP连接唯一地被通信两端的两个端点(即两个套接字)所确定

(3)TCP提供可靠交付的服务,无差错,不丢失,不重复,按序到达(可靠有序,不丢不重)

(4)TCP提供全双工通信

同一连接中能够传输双向数据流,拥有发送缓存和接收缓存
发送缓存:准备发送的数据和已经发送但尚未收到确认的数据
接收缓存:按序到达但尚未被接收应用程序读取的数据和不按序到达的数据
在这里插入图片描述

(5)TCP面向字节流

TCP把应用程序交下来的数据仅看成是一连串的无结构的字节流
(UDP是面向数据报的)

(5)流水线机制

TCP拥塞控制和流量控制机制设置窗口尺寸

(6)流量控制机制

2.TCP报文段

TCP传送的数据单元称为报文段, 一个TCP报文段分为TCP首部TCP数据两部分,整个TCP报文段作为IP数据报的数据部分封装在IP数据报中,其首部的前20B是固定的。

TCP报文段的首部最短为20B,后面有4N字节是根据需要而增加的选项,通常长度为4B的整数倍

TCP报文段既可以用来运载数据,又可以用来建立连接、释放连接和应答

在这里插入图片描述
(1)源端口和目的端口字段: 各占2B, 端口是运输层与应用层的服务接口,运输层的复用和分用功能都要通过端口实现

(2)序号字段:占4B,TCP是面向字节流的(即TCP传送时是逐个字节传送的),所以TCP连接传送的数据流中的每个字节都编上一个序号,序号字段的值指的是本报文段所发送的数据的第一个字节的序号,建立TCP连接时,双方随机选择序列号

(3)确认号字段:占4B, 是期望收到对方的下一个报文段的数据的第一个字节的序号若确认号为N,则表明到序号N- 1为止的所有数据都已正确收到

(4)首部长度(数据偏移):占4位,这里不是IP数据报分片的那个数据偏移,而是表示首部长度,它指出TCP报文段的数据起始处距离TCP报文段的起始处有多远

(5)保留字段

(6)紧急位URG:URG= 1时,表明紧急指针字段有效,它告诉系统报文段中有紧急数据,应尽快传送(相当于高优先级的数据), 但URG需要和紧急指针配套使用,即数据从第一个字节到紧急指针所指字节就是紧急数据

(7)确认位ACK:只有当ACK= 1时确认号字段才有效;当ACK=0时,确认号无效。TCP规定,在连接建立后所有传送的报文段都必须把ACK置1

累计确认:该序列号之前的所有字节均已被正确接收到

序列号和ACK传输示例:
在这里插入图片描述
主机A需要序列号为79的数据,发送TCP报文数据第一个字节的序列号为42,需要数据为’C’, 主机B发送数据’C’,和数据的第一个字节的序列号,ACK=43,说明前42个字节都收到,然后主机A在回复。

(8)推送位PSH (Push): 接收TCP收到PSH= 1的报文段,就尽快地交付给接收应用进程而不再等到整个缓存都填满后再向上交付

(9)复位位RST (Reset):当 RST=1时,表明TCP连接中出现严重差错,如主机崩溃,必须释放连接,然后再重新建立运输连接

(10)同步位SYN: 同步SYN= 1表示这是一个连接请求或连接接收报文
当SYN=1, ACK=0时,表明这是一个连接请求报文,对方若同意建立连接,则在响应报文中使用SYN=1, ACK=1,即SYN= 1表示这是一个连接请求或连接接收报文

(11)终止位FIN (Finish): 用来释放一个连接,FIN= 1表明此报文段的发送方的数据已发送完毕,并要求释放传输连接

(12)窗口字段它指出现在允许对方发送的数据量,接收方的数据缓存空间是有限的,因此用窗口值作为接收方让发送方设置其发送窗口的依据,单位为字节,一般用来限制发送方发送数据的

假设假设确认号是701,窗口字段是1000,这表明,从701号算起,发送此报文段的接收方方还有接收1000B数据(字节序号为701 ~1700)的接收缓存空间

(13)校验和:和UDP校验和一样的

(14)紧急指针字段:指出在本报文段中紧急数据共有多少字节,紧急数据放在本报文段数据的最前面

(15)选项字段

(16)填充字段

二、TCP可靠数据传输

1.概述

(1)TCP在IP层提供的不可靠服务基础上实现可靠数据传输服务

(2)流水线机制(滑动窗口协议)
滑动窗口协议–>GBN,SR

(3)累积确认

(4)TCP使用单一重传定时器

(5)触发重传的事件 : 超时 或者 收到重复ACK

(6)渐进式:流量控制,拥塞控制,重复ACK

这里前面大部分已经说过来,主要讲TCP超时重传时间的选择,后面会讲渐进式

2.超时重传时间选择

TCP的发送方在规定的时间内没有收到确认就要重传已经发送的报文,超时重传难点在于如何设置定时器的超时时间?

TCP采用了一种自适应算法,它记录一个报文段发出的时间,以及收到相应的确认的时间, 这两个时间之差就是报文段的往返时间RTT

加权平均往返时间

SampleRTT: 测量从段发出去到收到ACK的时间(忽略重传)
测量多个SampleRTT,求平均值,形成RTT的估计值EstimatedRTT
在这里插入图片描述

定时器设置的超时重传时间RTO(Retransmission Time-Out)应该稍微大于估计值EstimatedRTT

定时器超时时间的设置:
在这里插入图片描述
DevRTT:SampleRTT与EstimatedRTT的差值
在这里插入图片描述

Karn 算法
在计算平均往返时间RTT时,只要报文段重传了, 就不采用其往返时间样本

TimeoutInterval = TimeoutInterval(last)*y

TCP发送方事件
(1)从应用层收到数据
创建Segment,序列号是Segment第一个字节的编号,开启计时器,设置超时时间:TimeOutInterval

(2)超时
重传引起超时的Segment并重启定时器

(3)收到ACK
如果确认此前未确认的Segment ,更新SendBase,如果窗口中还有未被确认的分组,重新启动定时器

TCP发送端程序

NextSeqNum = InitialSeqNum TCP发送端程序
SendBase = InitialSeqNum
loop (forever) 
{
	switch(event)
	
	event: data received from application above
	create TCP segment with sequence number NextSeqNum
	if (timer currently not running)
		start timer
	pass segment to IP
	NextSeqNum = NextSeqNum + length(data)
	
	event: timer timeout
	retransmit not-yet-acknowledged segment with
	smallest sequence number
	start timer
	
	event: ACK received, with ACK field value of y
	if (y > SendBase) 
	{
		SendBase = y
		if (there are currently not-yet-acknowledged segments)
		start timer
	}
} /* end of loop forever */

重传示例
在这里插入图片描述
丢失ACK:当定时器时间超时,发送方就会重新发送报文
定时器时间设置过短:发送方一下发送两个报文,当第一个报文还没有返回给发送方,时间超时,发送方会再次发送报文,过一会,服务器的报文到达发送方,返回ACK=100,ACK=120,第二次的报文返回ACK=120,因为都收到了两个报文返回

3.快速重传机制

TCP的 实现中,如果发生超时,超时时间间隔将重新设置,即将超时时间间隔加倍,导致其很大

通过重复ACK检测分组丢失,Sender会背靠背地发送多个分组,如果某个分组丢失,可能会引发多个重复的ACK,如果sender收到对同一数据的3个ACK,则假定该数据之后的段已经丢失在定时器超时之前即进行重传(快速重传)

快速重传算法

event: ACK received, with ACK field value of y
	if (y > SendBase) 
	{
		SendBase = y
		if (there are currently not-yet-acknowledged segments)
		start timer
	}
	else  //进行快速重传
	{
		increment count of dup ACKs received for y
		if (count of dup ACKs received for y = 3) 
		{
			resend segment with sequence number y
		}
	......

三、TCP流量控制

流量控制 :发送方不会传输的太多、太快以至于淹没接收方(buffer溢出)
TCP利用滑动窗口机制实现流量控制

在通信过程中,接收方根据自己接收缓存的大小,动态地调整发送方的发送窗口大小,这称为接收窗口, 即调整TCP报文段首部中的“窗口”字段值,来限制发送方向网络注入报文的速率

发送方根据其对当前网络拥塞程序的估计而确定的窗口值,这称为拥塞窗口其大小与网络的带宽和时延密切相关

接收方为TCP连接分配buffer
在这里插入图片描述
Buffer中的可用空间 :
spareroom= RcvWindow
= RcvBuffer-[LastByteRcvd -LastByteRead]

Receiver通过在Segment的头部字段将RcvWindow 告诉Sender,Sender限制自己已经发送的但还未收到ACK的数据不超过接收方的空闲RcvWindow尺寸

四、TCP连接管理

TCP连接的建立采用C/S模式,主动发起连接建立的应用进程叫做客户,而被动等待连接建立的应用进程叫做服务器
在这里插入图片描述
TCP sender和receiver在传输数据前需要建立连接
建立连接前的准备:
(1)初始化TCP变量

1.Seq,标明本次报文段数据部分的第一个字节的序号
2.Buffer和流量控制信息

(2)Client:连接发起者

Socket clientSocket = new Socket("hostname","port number");

(3)Server: 等待客户连接请求

Socket connectionSocket = welcomeSocket.accept();

1.连接建立 — 三次握手

TCP建立过程图解
在这里插入图片描述

第一步:客户机的TCP首先向服务器的TCP发送一个连接请求报文段,这个特殊的报文段中不含应用层数据SYN标志位被置为1。客户机会==随机选择一个起始序号 seq=client_isn ==(连接请求报文不携带数据,但要消耗一个序号)

第二步:服务器的TCP收到连接请求报文段后,若同意建立连接,就向客户机发回确认,并为该TCP连接分配TCP缓存和变量,在确认报文段中,SYN和ACK位都被置为1(图中没有ACK), 确认号字段的值为ack=client_isn+ 1, 并且服务器随机产生起始序号seq = server_isn(确认报文不携带数据,但也要消耗-一个序号),确认报文段同样不包含应用层数据

第三步:当客户机收到确认报文段后,还要向服务器给出确认,并且要给该连接分配缓存和变量,报文段的ACK标志位被置1,序号字段为client_isn+ 1,确认号字段ack= server_isn+1, 该报文段可以携带数据,若不携带数据则不消耗序号

成功进行以上三步后,就建立了TCP连接,接下来就可以传送应用层数据

注:
(1)服务器端的资源是在完成第二次握手时分配的

(2)客户端的资源是在完成第三次握手时分配的,这就使得服务器易于受到SYN洪泛攻击

SYN洪泛攻击
攻击者发送TCP SYN,服务器返回ACK后,该攻击者就不对其进行确认,那么这个TCP连接处于挂起状态,所谓的半连接状态服务器收不到再确认的话,还会重复发送ACK给攻击者,这样就更加浪费服务器资源

攻击者如果发送非常大量的这种TCP连接,由于每一个都无法完成三次握手,所以服务器上这些TCP连接会因为挂起状态而消耗CPU和内存,最后服务器可能死机,就无法为正常用户提供服务

解决办法:SYN cookie

2.连接释放 — 四次挥手

连接释放过程图解
在这里插入图片描述
第一步:客户机打算关闭连接时,向服务器发送一个连接释放报文段, 并停止发送数据,主动关闭TCP连接,该报文段的FIN标志位被置1, seq=u(它等于前面已传送过的数据的最后一个字节的序号加1) ,FIN报文段即使不携带数据,也要消耗一个序号

TCP 是全双工的,即可以想象为一条TCP连接上有两条数据通路,但在发送FIN报文时,发送FIN的一端不能再发送数据,即关闭了其中一条数据通路,但对方还可以发送数据

第二步:服务器收到连接释放报文段后即发出确认,确认号是ack=u+ 1,这个报文段自己的序号是v(等于它前面已传送过的数据的最后一个字节的序号加1)

此时,从客户机到服务器这个方向的连接就释放了,TCP连接处于半关闭状态。但服务器若发送数据,客户机仍要接收,即从服务器到客户机这个方向的连接并未关闭

第三步:若服务器已经没有要向客户机发送的数据,就通知TCP释放连接,此时其发出FIN= 1的连接释放报文段

第四步:客户机收到连接释放报文段后,必须发出确认,在确认报文段中,ACK字段被置为1,此时TCP连接还未释放,必须经过时间等待计时器设置的时间2MSL后,客户机才进入连接关闭状态。但是,只要服务器收到客户机发送的确认就关闭。

注:关于连接和释放,ACK、 SYN、 FIN 一定等于1

连接过程中客户机和服务器的状态:
在这里插入图片描述

五、TCP拥塞控制

1.基本原理

拥塞控制指防止过多的数据注入网络,保证网络中的路由器或链路不致过载

出现拥塞时,端点并不了解到拥塞发生的细节,对通信连接的端点来说,拥塞往往表现为通信时延的增加

拥塞控制 VS 流量控制
相同点:它们都通过控制发送方发送数据的速率来达到控制效果

不同点:
拥塞控制是让网络能够承受现有的网络负荷,是一个全局性的过程,涉及所有的主机、所有的路由器,以及与降低网络传输性能有关的所有因素

流量控制往往是指点对点的通信量的控制,即接收端控制发送端,它所要做的是抑制发送端发送数据的速率,以便使接收端来得及接收

控制原理:
(1)Sender限制发送速率
通过设置CongWin(拥塞窗口)的大小,流量控制哪里介绍过

(2)CongWin(拥塞窗口):动态调整以改变发送速率,反映所感知到的网络拥塞

(3)如何感知网络拥塞?
Loss事件=timeout或3个重复ACK,发生loss事件后,发送方降低速率

(4)如何合理地调整发送速率?
1.加性增—乘性减: AIMD
2.慢启动: SS

2.慢启动(SS)

原理: 当连接开始时,指数性增长

在TCP刚刚连接好并开始发送TCP报文段时,先令拥塞窗口CongWin= 1,即一个最大报文段长度MSS

每收到一个对新报文段的确认后,将CongWin加1,即增大一个 MSS,用这样的方法逐步增大发送方的拥塞窗口CongWin,可使分组注入网络的速率更加合理,因为在开始的时候,可用带宽可能远远高于初始传输速率
在这里插入图片描述
指数性增长:每个RTT(也叫做传输轮次)将CongWin翻倍,收到每个ACK进行操作,初始速率很慢,但是快速攀升

3.加性增—乘性减(AIMD)

原理:逐渐增加发送速率,谨慎探测可用带宽,直到发生loss

加性增: 每个RTT将CongWin增大一个MSS——拥塞避免
乘性减: 发生loss后将CongWin减半也称为快恢复

何时应该指数性增长切换为线性增长(拥塞避免)?

设置变量 Threshold,当慢启动将拥塞窗口增大到Threshold慢启动阈值,改用AIMD(拥塞避免)
在这里插入图片描述

Loss事件发生时, Threshold被设为Loss事件前CongWin值的1/2(黑线是正确的)

例题: 一个TCP连接总是以1 KB的最大段长发送TCP段,发送方有足够多的数据要发送。当拥塞窗口为16 KB时发生了超时,如果接下来的4个RTT(往返时间)时间内的TCP段的传输都是成功的,那么当第4个RTT时间内发送的所有TCP段
都得到肯定应答时,拥塞窗口大小是多少?

threshold=16/2=8 KB, CongWin=1 KB, 1个RTT后, CongWin=2 KB ,
2个RTT后, CongWin=4 KB ,3个RTT后, CongWin=8 KB ,Slowstart isover;
4个RTT后, CongWin=9 KB

总结

提示:这里对文章进行总结:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Super.Bear

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值