TCP协议详解

TCP协议 简介

TCP 协议是属于传输层的协议 上一篇我们写了关于UDP协议的有关内容
在UDP中 我们知道他最大的传输数据是不能大于64kb 但在TCP协议中却不是这样的 TCP 在传输中提供了可靠的数据传输 和流控制机制 但是TCP由于在传输的过程中引入了较多的信息 因此TCP会比UDP传输的速度慢 .

TCP报文格式

要想了解一个协议 理解它的报文格式是很重要的.

下面就是TCP的报文格式:
在这里插入图片描述
16位源端口: 2个字节 表示发送请求端的端口号
16位目的端口号: 2个字节 表示接收方的端口号
**4位首部长度:**4位首部长度指的是 报头的长度 不是TCP报文的长度
这个长度是可变的 下面有个选项 意思就是可有可无 可以选一个 ,也可以选多个 , 在TCP报头中前面的20个字节是固定的 选项最多是40个字节.
4bit表示的范围是0~15 但是在这里TCP的首部长度的单位是4字节 所以最多是15 * 4 60个字节 .

保留位:
TCP这里的保留位只要解决的东西就是数据传输量大 空间不够的问题 我们知道在UDP中 就两个字节的报文长度 ,而且不能扩展 ,但在TCP就引入了保留位 就是申请了一部分空间 先不用 防止以后可以用上 这就体现了TCP的拓展性 如果后面TCP要引入一些新的功能 就可以使用保留位.

标志位: TCP中有6个标志位 也是TCP协议的灵魂所在 在后面我们讲到TCP的核心机制 就会用到标志位

确认应答机制

TCP协议的特点就是可靠传输 那TCP是怎么解决可靠传输的呢
这里所说的可靠传输 ,并不是说你只要发送了就能够百分百能把数据发给对方 ,但是会尽最大努力 ,而且可以让发送方知道,接收方是否收到.

举个栗子 : 就比如我给女神发消息 约她出来吃饭 !
在这里插入图片描述
我给女神发了一条信息 ,女神收到信息 就会给我回复一条 .在这里女神回复的"好啊 当然可以!" 这句话就相当于应答的数据 称为应答报文
这里的应答报文 也就是报文格式的标志位中的 ack

这样就属于确认应答 在TCP中 就是通过这种来保证可靠传输
发送端 发送一条数据给接收方 接收方收到就会给发送端返回一个ack 这就是TCP的确认应答机制.

但现在还有一个问题 ,就是你发多条数据过去 ,收到多条应答 但是很多时候可能会出现 后发先至 的情况 具体什么样子的 我们来举个例子 :
在这里插入图片描述
通过上面例子 : 就有这种情况出现 就是女神给的第二个的请求的应答比第一个请求先到达 这样就会让发送方 误解了.

那怎么办呢 ?
在这里TCP给每个字节分配一个序号 在报头中写的序号的数值 就是载荷部分的第一个字节的序号 ,这些序号都是递增的 只要知道第一个字节的序号,后面的每个字节的序号都知道了. 而确认序号的设计是在应答的数据中的最后一个字节的序号+1

在这里插入图片描述
通过上面的图片可以看出 对于主机B来说 小于501的数据已经接收 在向主机A索要501之后的数据 .

确认应答是保证TCP可靠传输的重要角色 ,但是在传输过程中出现丢包的情况该怎么办呢 在网络中 丢包现象很常见
而且丢包是客观存在 无法预测 .
在我们玩一些游戏的时候 丢包现象是十分敏感的 丢包率太高 你就玩不了了 比如一些竞技游戏 : 王者 LOL 等 .
出现丢包 数据就不会传输到接收方了 那怎么办呢?

超时重传

超时重传 就是用来应付网络出现丢包情况的
按照正常情况来说 TCP通过确认应答机制就可以知道数据是否被接收了
A可以根据是否收到ACK 来区分是否丢包

在A这边吧数据发送出去之后 直到收到ACK 会经过一段时间的
在这个时间内 A会进行一定的等待,如果超出等待时间的阈值 还没收到ACK 此时就可以认为出现丢包了 就会触发重传 超过那个阈值 也就是超时了 那个阈值是可以人为去设置的.

在这里是数据丢包了 触发超时重传 但如果是ACK发生丢包了 那该怎么办呢?
站在发送端的角度 是无法区分是数据丢包了 还是ACK丢包了 发送端就是发现超过时间没有收到ACK 他就会进行重传 ,重传之后接收方就会收到两份相同的数据
这种事情发生事十分不合理的

在TCP上无论重传和接收多少次都不影响 只要保证应用层 不能读到重复的数据就行 那怎么去重呢, TCP中在接收方 操作系统内核中会存在一个数据结构 “接收缓冲区” 类似于PriorityBlockingQueu 阻塞队列
就在这里也是生产者消费者模型 在TCP中 接收方收到数据 就会用一个阻塞队列存放着 放的过程中 会根据数据的序号,在队列中进行判断 判断这个数据是否在队列中存在 或者在队列中曾经存在过,只要存在过 这个新的数据就不会进入队列 而是直接丢弃

在这个缓冲区中不仅可以对数据去重 也可以对数据排序 这样就可以知道哪个数据曾经存在过 .

在网络中 丢包是一个概率性事件 假设网络丢包率是百分之10 重传之后再丢包的概率就会变为百分之1 了 .

超时重传 超出多少时间重传呢 这个时间是动态变化的
随着重传次数的变多 会变得越来越长

但如果网络确实出现故障了 重传了若干次 还是不成功 达到阈值之后 ,就会尝试重置连接 触发一个"复位报文"相当于重新连接 这里的复位报文就是TCP标志位中的RST 如果RST都解决不了 就只能断开连接了.

连接管理

连接管理分为 : 建立连接的流程 : 三次握手 和断开连接的过程 : 四次挥手 .
在握手和挥手的过程中 传输的是网络数据报 ,没有携带任何业务上的数据.

三次握手

握手就是两个主机 一见面,然后进行打招呼,在打招呼的过程中,没有实质上数据交互 就是为了打招呼而传输的一些数据
建立连接 ,就是通信双方 ,各自保存对端的信息 上诉过程就需要三次网络交互 三次握手的第一次 一定是客户端先发起的 也就是说谁先发起 谁就是客户端 下面我们就通过图片来感知一下三次握手是怎么样的
在这里插入图片描述
SYN 这个报头它的载荷是空着的 只有TCP报头
这里的SYN也是TCP标志位中的一个 其实是synchronized的前三个字母
和Java锁的关键字一样 这里的意思是同步的意思 在多线程中 同步的意思可以理解成互斥 在TCP中 "同步"则是希望 客户端和服务器之间达成某种关联关系.

上诉握手的流程就是 客户端和服务器各自给对方发送SYN
再各自给对方返回一个ACK 其实是四次交互
关键在于 中间的 两次交互ACK和SYN可以合并成一个数据
ACK是6个标志位的第二位 SYN是6个标志位中的第五位 所谓的合并就是这个数据包中的报头中同时把两个比特位设置为1 .

这样就变成三次交互了 与四次交换 比起来效率更高 .

三次握手的意义

1 三次握手相当于投石问路 在正式传输业务数据之前,先确认一下通信链路是否畅通 相当于hiTCP可靠传输的一种保证 但是这里的握手 只是辅助机制 TCP保证可靠传输的核心还是确认应答和 超时重传

2 通过三次握手 来确认通信双方,发送能力和接收能力都是正常的 进行三次握手 本质上就就是完成上诉过程

相当于 我们两个人开黑 不是面对面 而要通过打QQ电话 我们=一开始是互相不知道对方的耳机和麦克风是否是正常的 我们可以通过几次沟通来辨别 这几次就是来确认双方的通信能力 .

3 三次握手的过程中 还可以协商一些必要的参数 有的参数不是单方面确认的,而是需要双方共同确认出来的 比如说确认骑士序号

TCP状态

在这里插入图片描述
通过上图 只要有两个重要状态 LISTEN :是服务器才会有的状态 当服务器绑定的端口成功后就会进入该状态 此时就表示可以u客户端连接上来了

WSTABLISHED状态 表示建立连接完成 可以随时进行后续的通信了.

四次挥手

四次挥手,你 挥手 客户端和 服务器都可以发起请求 就类似 谈恋爱 分手 谁都可以提出 这里我们以客户端主动提出为栗子 画个图 :
在这里插入图片描述
断开连接 就是把之前保存的对方的信息给删了

服务器 收到 客户端的结束报文 FIN 就会立即返回ACK
但是服务器的 FIN结束报文 要在应用程序代码中调用close的时候才会触发 (代码控制着)
服务器返回ACK 和FIN 这两个操作不是同一时机的 中间可能隔很久
正常情况下 都是 四次挥手 但是有特殊情况 上诉那两个操作可以合并 就是TCP中有一延时应答机制 (不是立刻回复ACK 而是要等一段时间)
因为一般情况下都是四次挥手 最终就把断开连接 称为"四次挥手".

在这里插入图片描述
在上诉有一个状态 CLOSE WAIT : 被动的一方会进入的状态 等待代码调用 CLOSE
如果服务器这边出现大量的CLOSE_WAIT 说明代码有bug 代码很可能忘记调用CLOSE 或者调用CLOSE 不及时 .

还有一个TIME-WAIT : 这个状态就是持续一段时间等待对方的FIN重传 等待的时间一般是2MSL 过了这段时间吧 就默认对方不会重传了

如果服务器出现大量的TIME_WAIT 说明服务器 这边触发了大量的主动断开TCP连接的操作
但是这种操作是不合理的 一般都是 客户端主动断开连接 .

滑动窗口

TCP 除了 要保证可靠传输之外 ,也希望能够尽可能高效的完成数据传输 ,滑动窗口 就是一种提高传输效率的机制
在没有引入滑动窗口之前 客户端这边每次收到一个ACK 才会发送下一个数据 这样的过程就比较低效 .
引入窗口后的效果 就是 :
在这里插入图片描述
一条一条发送就变成了批量发送 这样等待的时间就重叠了 批量发送 也要等待一会ACK
如果完全不等 一直完后发 可靠性也不能保证.
就比如上面的滑动窗口 一下子 把0~4000的数据都发送了 如果他收到了 2001ACK 说明前面的数据都发送到了 窗口就会往后滑 没收到一个ACK 就会滑动一个窗口 使窗口大小一直保持不变 .
假如 滑动窗口中发生丢包该怎么办 ? 这种情况发生还是要保证可靠性

第一种情况: 数据包已经到达 ACK发生丢包了
在这里插入图片描述
这种情况发生在滑动窗口中 其实是无关紧要的 只要不是ACK全丢了就行 因为在滑动窗口中只要比你大的确认序号返回了 就说明前面的数据被接收了 出现 ACK丢包的情况 可以不做任何处理 也不会产生问题的 . 确认序号的设计 巧妙的解决了 ACK丢包的问题 .

第二种就是数据包发生丢包了

在这里插入图片描述
通过观察 上面的图片会发现 1001~2000的数据包发生丢包了 注意每个ACK确认序号的变化 ,尽管主机A 仍然在继续给主机B发送数据包 但是接下来的每个数据 B都向A索求1001 这个数据包 这时 B向A索求几次之后 A就知道了 1001 ~2000这个数据丢失了 这样主机A就会把缺失 的数据进行重传即可,其他 的数据不比重传 这里涉及 的重传是快速重传 (在滑动窗口下 ,是搭配的丢包处理机制 ) 这里补上缺失 的数据之后 接下来就从队列中最后一个数据的序号继续往后索要 .

在这里所使用到的快速重传 和之前用的超时重传 其实并不冲突 快速重传 其实是超时重传的特殊变种 如果TCP传输的数据比较少 ,也就不会触发滑动窗口.

就算TCP用了滑动窗口这种机制 他传输数据的速度 也不可能比得过 UDP .

流量控制

上面我们讲了有关滑动窗口的有关内容
这里的流量控制 涉及到的关键概念就是窗口大小 就是批量发送的数据量

窗口大小其实是可变的 可以通过窗口大小来控制发送方的速度
窗口越大 单位时间发的数据 就越多 ,效率就越高
窗口越小 单位时间发的数据就越少.

通常情况下 ,肯定是希望,尽可能高效的传输数据 但如果发送的太快 可能会变得不可靠 极大可能引起丢包 .

接收方可以根据自身的处理能力,反向制约发送方的速度 使双方达成一个平衡状态 这样的机制就称为"流量控制".
其实就是通过一个接收缓冲区相当于一个阻塞队列 来控制

在TCP中会有一个空闲空间大小 作为发送数据的窗口大小 ,这个数值会通过接收方告诉给发送方 会返回一个ACK 报文中会指定一个字段来表示空闲的空间大小.在TCP 报问格式中有一个16位窗口大小 这个就是用来表示空闲空间大小的 他的最大空间不仅仅是64kb 在选项中会有一个窗口扩展因子 .

拥塞控制

和流量控制一样 也是搭配滑动窗口使用的机制

这个要考虑传输的时候中间经过很多东西 要考虑中间节点
我们可以通过实验的方法找窗口大小
刚开始的时候 我们先用比较小的速度,小的窗口来发送数据
如果没有发生丢包 说明中间的节点 通畅 可以继续增加速度 增加窗口大小 加到一定的程度 如果出现丢包的情况 我们就立即减少窗口大小 ,继续发送 看是否出现丢包 不丢包再继续添加 在不丢包的边缘疯狂试探.

上面就是拥塞控制 流量控制的窗口也会影响 发送速度 拥塞控制窗口也会影响发送速度 但选哪个窗口呢 这里我们就要根据木桶效应
哪个小选择哪个.

在这里插入图片描述
上面图片就是拥塞控制的变化过程 上面的过程就像谈恋爱 的过程差不多

延时应答

延时应答就是ack不会立即返回 而是等一会再返回 延时就是为了提升传输的效率 只要是可以提高窗口的大小 因为延时就会给应用程序腾出消费时间 这样 空闲的空间就变大了 窗口大小就变大了.

延时时间 有两种方式 都是结合使用
1 按照一定的时间来指定延时
2 按照收到的数据量

捎带应答

捎带应答 建立在延时应答的基础上 ,提升效率的机制
日常开发中, 客户端服务器之间的通信 一般都是一问一答这样的机制
就是客户端发送请求 正常来说 ack是内核收到请求就自动返回了
但是由于延时应答的存在 ack 不会立即返回 ack在等待的时间时候,正好返回相应数据 ,此时,就在响应数据中,tcp中的ack 这一位设置上 .

这样的效果 就是 把两次传输 合并成一次传输.
就相当于叫舍友顺便带东西一样.

粘包问题

粘包问题 在字节流读写数据的时候 涉及到的一个十分关键的问题
就是在传输数据的时候 应用层的数据包粘在一起了 我们应该怎么分开 就是怎么区分那个是一个完整的应用层数据包 明确包之间的界限

1 我们可以使用分隔符
定义任何字符都行 ,只要不是数据的内容就行

2 约定包的长度

异常情况

1 . 其中某个进程崩溃了
进程不管是崩溃还是正常结束 操作系统都能够回收释放对应的PCB释放里面的文件描述符表 相当于调用了close 此时还是可以进行四次挥手 虽然进程不在了 但是操作系统还是会管理着tcp的连接 可以顺利和对方挥手完 .

2 某个主机被关机 正常关机
这种关机 操作系统都会先提醒你 要结束所有用户进程 不然会强制结束 进入关机状态 结束进程之后,会进行四次挥手 就相当于 A和B 建立连接 A这边关机了 A关机之前 把FIN传给B B这边收到了FIN,B 返回ACK 准备发送FIN 但是此时A关机了 意味着B 下来会重传几次
之后还是没有ACK的话 还是会把A给删除了 A关机了 也就没有 了B的信息.

3 某个主机电源突然坏了 掉电了
比如 A和B进行通信 A突然掉电了 A无法做出反应就无了 B还以为A还活着
'这时候 如果B是发送方
B就不会有ACK了 B 就会触发重传 重传几次之后,就会发送复位报文(RST) RST 如果也没有反应 B 就会单方面的把A给删了

如果B是接收方
接收方 不知道对方啥时候给自己发数据
B在一定的时间内没收到A的数据之后,就会触发心跳包 心跳包也是有周期的 是一个没有载荷的数据包 为了触发ACK的. 触发心跳包之后还是没有ACK返回的话 说明A就是无了 B就会单方面的删除A.

4 网线断开
这种情况其实和第三种情况是一样的.

上面的所有的内容 是TCP中的一些重要机制 10大机制 属于我们程序员的内功 要好好掌握

谢谢大家的观看 !!!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值