文章目录
- 前言
- 一、TCP协议段与机制
- TCP协议的特点
- TCP报头结构
- TCP协议的机制与特性
- 二、TCP协议的 面向字节流特性
- TCP协议接发数据的流程
- TCP协议面向字节流导致的BUG
- 三、TCP协议的 异常情况
- 总结
前言
本人是一个普通程序猿!分享一点自己的见解,如果有错误的地方欢迎各位大佬莅临指导,如果这篇文章可以帮助到你,劳请大家点赞转发支持一下!
本文讲解了TCP的两大特性以及沾包问题的解决方案
一、TCP协议段与机制
TCP协议的特点
特点 | 说明 |
---|---|
有连接 | 刻意保存对端的相关信息 |
可靠传输 | 尽全力将数据传输过去不是百分百成功,自己会知道数据传输是否成功 |
面向字节流 | 以一个字节为基本单位(一个数据可以分成几份 多次发多次收) |
有接收缓冲区,也有发送缓冲区 | 接收缓冲区:接收方用一个特殊的数据结构来组织接收到的数据,使用数据就从接收缓冲区拿,然后接收缓冲区就会删除已经拿走的数据。 发送缓冲区:发送方将要发送的数据存入发送缓冲区,等发送缓冲区满了,才会集中发送一次,可能会导致BUG(数据写到了发送缓冲区而没有发送出去),因此代码中发送数据时尽量刷新缓冲区 |
大小不受限 | 对于要传输的数据大小没有要求 |
全双工 | 一条通信路径,双向通信。(可以同时发送和接收数据) |
TCP报头结构
6位标志位
TCP协议的机制与特性
TCP的协议段格式,比UDP的协议段格式复杂一万倍!😵😵
所以他的机制与功能也比UDP更加强大!!😇😇
TCP对数据传输提供的管控机制,主要体现在两个方面: 安全和效率 。
这些机制和多线程的设计原则类似: 保证数据传输安全的前提下,尽可能的提高传输效率 。
TCP协议的机制与特性
1️⃣确认应答
2️⃣超时重传
3️⃣连接管理
4️⃣滑动窗口
5️⃣流量控制
6️⃣拥塞控制
7️⃣延时应答
8️⃣捎带应答
9️⃣面向字节流
🔟异常处理
- 1️⃣-5️⃣是TCP协议保证数据传输安全的 安全机制 。TCP协议的三大安全机制
- 6️⃣-8️⃣是TCP协议提高传输效率的 效率机制 。TCP协议的五大效率机制
- 9️⃣-🔟是TCP协议的 两大特性 。
二、TCP协议的 面向字节流特性
TCP协议接发数据的流程
创建一个TCP的Socket,同时在内核中创建一个 发送缓冲区 和一个 接收缓冲区。
因此TCP协议的发送接收数据就有以下几个特点。
发送数据时
1️⃣调用write时,数据以字节流的形式会先写入发送缓冲区中。
2️⃣如果发送的字节数太长,会被拆分成多个TCP的数据包发出。
3️⃣如果发送的字节数太短,就会先在缓冲区里等待,等到缓冲区长度差不多了,或者其他合适的时机发送出去。
接收数据时
4️⃣数据也是从网卡驱动程序到达内核的接收缓冲区。
5️⃣然后应用程序可以调用read以字节流的形式从接收缓冲区拿数据。
TCP协议面向字节流导致的BUG
因为有接收缓冲区与发送缓冲区的存在。
TCP协议在发送数据时,实际上是发送方将数据写入到了发送缓冲区,由发送缓冲区来完成发送数据。
TCP协议在接收数据时,实际上是由接收缓冲区来接收数据,然后接收方再从接收缓冲区来读取数据。
那么这就导致了两个BUG。
1️⃣BUG原因: 我要发送的数据如果太小,可能会存入接收缓冲区中,而没有发送到对端 。
解决方案: 很简单,通过响应的输出流对象来调用flush()方法,强制刷新发送缓冲区,以达到发送的目的 。
2️⃣BUG原因 我读取数据是从接收缓冲区中直接拿数据,他与UDP协议不同 。
UDP协议采用数据报进行发送接收,每条数据都单独装在一个数据报里,因此可以很容易的区分每条数据 。
TCP协议会针对每个对端都分配,接收缓冲区,发送缓冲区,专门针对这两个设备间的输入输出流 。
TCP协议接收数据是从网卡驱动程序到达内核的对应的接收缓冲区(到达接收缓冲区时,已经把TCP报头分用过了,就剩应用层数据了 ),再从接收缓冲区中采用专门的输入流来读取数据,
如果对端发送过来多条数据,每条数据大小不一,此时就会出现沾包问题(读了半条数据,读了一条半数据,即读不到一条完整的数据) 。
解决方案: 导致出现沾包问题的原因就是:每条数据之间没有明显的界限。因此解决方案就是自定义一个应用层协议来给每条数据一个明显的界限。(应用层协议还有许多其他功能,不单单是为了解决沾包问题,后续文章会为大家介绍的)
常用两种方法:
1️⃣分隔符:在结尾处加上分隔符来区分每条数据。
2️⃣约定长度:规定每条数据前四个字节为整条数据的长度,然后根据前四个字节在读取时,读取对应长度。
三、TCP协议的 异常情况
此处的异常情况指的是一些特殊情况下一端断开连接,另一端如何处理。
1️⃣进程关闭 / 进程崩溃
此时,进程没了,Socket这个文件也随之关闭了,但是连接还在,仍然可以正常的完成四次挥手来断开连接。
2️⃣主机关机(正常流程关机)
主机关机会先杀死所有的用户进程,此时就同上,进程仍然会
触发四次挥手。
1. 主机向对端发送FIN
2. 对端收到返回ACK
3. 对端向主机发送FIN
4. 主机收到返回ACK
但是有两种情况。
关机前完成了四次挥手
也就是说这四次手正常挥完,然后断开连接。
四次挥手还没完成就已经关机了
可能第一 / 二 / 三次挥手完成之后,主机就关机了。
也就是说主机没有向对端返回ACK,不用担心。
那么此时对端会怎么做呢?
对端触发超时重传,重新发送FIN =》重传几次仍没有收到ACK,尝试重置连接 =》仍收不到ACK,释放连接
也就是无论四次手挥没挥完都会达到断开连接的效果。
3️⃣主机(台式机)突然断电
主机突然断电,那么此时就来不及做任何操作,因此就无法完成四次挥手来断开连接。
此时就分为两种情况:
断电主机为接收方,对端是发送方
那么此时对端仍然进行发送操作,但是此时接收方断电,因此就无法返回ACK,而对端收不到ACK,就会执行下列操作。
对端触发超时重传 =》重传几次仍没有收到ACK,尝试重置连接 =》仍收不到ACK,释放连接
断电主机为发送方,对端是接收方
这就不太好办了,不知道他是没发消息,还是掉线了,那么要如何区分呢?
别担心,TCP大佬替我们解决了。
TCP内置了一个保活定时器,会定期的向对端发送一个数据包(心跳包),查看对方是否还在线,如果不在,就会把连接释放掉。
无论哪一方突然断电,TCP都会断开连接。
4️⃣网线断开
同上
总结
以上就是今天要讲的内容,本文介绍了TCP协议的两大特性以及沾包问题的解决方案。
路漫漫不止修身,也养性。