概述
TCP(Transmission Control Protocol)传输控制协议
和UDP结构类似,由TCP首部和TCP数据报数据组成:
特点:
- TCP是面向连接的协议
- TCP的一个连接有两端(点对点通信,类似打电话?)
- TCP提供可靠的传输服务
- TCP提供全双工的通信
- TCP是面向字节流的协议(对应用层数据报合并或分拆)
TCP协议头部,固定20个字节,UDP头部只有8个字节,IP协议头部20个字节:
序号:
- 0~ 2^32-1
- 一个字节一个序号
- 数据首字节序号(第一个字节)
确认号:
- 0~ 2^32-1
- 一个字节一个序号
- 期待收到数据的首字节序号
- 确认号为N:表示N-1序号的数据都已经收到
比如,收到了序号为501的数据报,长度是100,下一次确认号则为601
数据偏移:
- 占4位:0~15,单位为:32位字(由此可以看出最大偏移为15*4,即TCP首部长度介于20-60个字节之间)
- 数据偏离首部的距离
- 不知道TCP选项有多长,所以用数据偏移表示真实的数据离头部偏移有多少
TCP标记:
- 占6位,每位各有不同意义
URG、ACK、PSH、RST、SYN、FIN:
窗口:
- 占16位:0~2^16-1
- 指明允许对方发送的数据量(比如确认号501,窗口是1000,那么501-1500都是可以接收的)
紧急指针:
- 紧急数据(URG=1)
- 指定紧急数据在报文的位置
TCP选项:
- 最多40字节(60-20)
- 支持未来的拓展
可靠传输的基本原理
停止等待协议:
- 发送方等待接收方的确认消息,才发送新的信息
- 最简单的可靠传输协议
- 通过超时重传保证可靠传输
- 对信道的利用效率不高
停止等待协议,无差错的情况:
出差错的情况,超时重传,包括接收方没有收到发送方的消息:
超时重传,发送方没有收到接收方的确认信息:
超时重传,确认消息很久才收到:
小结:
- 发送的消息在路上丢失了
- 确认的消息在路上丢失了
- 确认的消息很久才到
停止等待协议通过超时重传保证可靠传输
超时定时器:
- 每发送一个消息,都需要设置一个定时器
连续ARQ协议:
- ARQ(Automatic Repeat reQuest)自动重传请求
- 批量发送和确认
- 滑动窗口和累计确认是其两个重要概念
滑动窗口,收到前面的确认消息,滑动窗口向前移动,把滑动窗口内的未发送消息发送出去:
并不需要对每一个报文都确认,而采用累计确认的方法。如收到了5的确认消息,则认为1-5的消息都已经收到了,就把滑动窗口往前移动5格:
TCP协议的可靠传输
1. TCP的可靠传输基于连续ARQ协议
2. TCP滑动窗口以字节为单位
滑动窗口里面的7个字节都是可以发送的,左边是已经确认的字节序号,右边是不允许发送的字节序号,窗口内最左边是对方期待收到的下一个字节
窗口内又可分为已发送未确认和可用窗口,由于没收到前面的确认所以不能往前移动:
有可能窗口内都是已发送未确认,可用窗口=0。
没有按序收到确认消息,即收到后面的确认消息,但是没收到前面的,超时后,会从前面开始重传,效率低:
选择重传:
- 选择性的重传某些消息,而不是重传所有消息
- 选择重传需要指定需要重传的字节
- 每一个字节都有唯一的32位序号
TCP选项最多40个字节(60-20),即最多10个序号,指定的是需要重传的边界,而不是字节,表明需要重传的一段范围
一段一段,如果里面存了1000和1500,指的是需要重传1000~1500这一段数据
TCP协议的流量控制
1. 特有的功能(UDP和其他协议没有)
2. 流量控制指让发送方发送速率不要太快
3. 流量控制是使用滑动窗口来实现的(确认号是501的话,如果窗口是1000,表明接收方希望接收501-1501的数据)
通过窗口大小控制对方发送速率:
如果丢失了最后的确认窗口变大(不为0)的消息,就会导致死锁,发送方一直等到对方窗口变大,接收方一直等待对方发送消息
坚持定时器(解决死锁):
- 当发送方接收到窗口为0的消息,则启动坚持定时器
- 坚持定时器每隔一段时间发送一个窗口探测报文
这种死锁相当于情侣一方A一直等待对方B改变脾气,而B已经改变了,但联系不到A,坚持定时器是A每隔一段时间问一下B,你改变了没有
TCP协议的拥塞控制
1. 一条数据链路经过非常多的设备
2. 数据链路中各个部分都有可能成为网络传输的瓶颈(导致拥塞)
与流量控制的区别:
- 流量控制考虑点对点的通信量的控制
- 拥塞控制考虑整个网络,是全局性的考虑
- 报文超时则认为是拥塞(虽然不一定)
慢启动算法:
- 由小到大逐渐发送数据量
- 每收到一个报文确认,就加一(指数增长,1 2 4 8 16…)
- 增长到慢启动阈值(ssthresh)后就不增长了
拥塞避免算法:
- 维护一个拥塞窗口的变量
- 只要网络不拥塞,就试探着把拥塞窗口调大(比如到了慢启动阈值16后,以后发送17、18、19…个报文)
二者结合,先进行慢启动算法,再进行拥塞避免算法:
上述过程就像一个人贪婪的过程
TCP连接的三次握手
涉及到3个TCP标记,SYN(连接请求)、ACK(代表已确认)、FIN(代表释放连接)
1.发送方发送:SYN=1, seq=x
2.接收方发送:SYN=1, ACK=1, seq=y, ack=x 1(小写的ack表示期望收到序列号的值是x 1,seq=y表示自己携带的序号为y)
3.发送方发送:ACK=1, seq=x 1, ack=y 1
- 第一次和第二次握手都有SYN标记位,代表连接请求的意思
- 第二次和第三次都有ACK的标记,对连接双方的序列号进行同步(都知道对方的序列号)
- 发送方在第二次握手后就建立连接了,接收方在第三次握手后才建立连接,双方都建立连接后就可以进行数据传输了
- 发送方发送第一次报文后进行同步已发送(SYNC-SENT)状态;
- 接收方收到之前处于监听(Listen)状态,收到第一次报文后进入同步已接收(SYNC-RCVD)状态;
- 发送方收到第二次报文后进行连接(ESTABLISHED)状态;
- 接收方收到第三次报文后进入连接(ESTABLISHED)状态。
- 即发送方状态为:同步已发送、建立连接。接收方状态为:监听、同步已接收、建立连接
- 最早,接收方和发送方都是closed状态,即关闭。
为什么发送方要发出第三个确认报文(为什么需要第三次握手)?
- 防止已经失效的连接请求报文传送到对方,引起错误
详细解释:
- 发送方第一次握手时发送很久没有收到对方应答,于是发送了第二封,第二封比第一封更早到达,第一次便是失效的请求报文
- 如果两次握手就能建立起连接:同一个请求发送两次(第一次超时)就会建立起两个连接,引起错误
- 本来这是一个早已失效的报文段,但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。
虚线是假设两次握手就建立连接
TCP连接的四次挥手
比三次握手多出来的是第二次挥手,意思是我收到了,但是我现在还没传完,等会关闭
- 主动关闭的一方状态变化为:建立状态、第一次等待(FIN-WAIT-1)、第二次等待(FIN-WAIT-2)、等待计时(TIME-WAIT)、关闭
- 被动关闭的一方状态变化为:建立状态、关闭等待(CLOSE-WAIT)、最后确认(LAST-ACK)、关闭状态。
- 主动关闭的一方最后有等待计时状态
MSL(MAX Segment Lifetime):最长报文段寿命
- MSL建议设置为2分钟
等待计时器
- 最长等待时间2MSL
- 等待过程中,不会释放端口,只有等到等待计时器结束后,才释放