目录
源端口:
- 指发送方的端口号
目的端口:
- 指接收方的端口号
注意:
- 端口号都是用两个字节来表示的,也就是16个比特位,也就是能表示 0~65535 的端口号范围
- 其中 0~1023 端口称为 知名端口号,这些端口号已经分配给了一些广泛使用的知名应用程序,所以当我们自己进行端口的绑定时,得从 1024 端口号开始!
UDP报文长度:
- UDP报文 长度为 2 个字节,所以可以表示一个 UDP数据报 的长度范围为 0~65535 字节,也就是 0~64 KB 的数据
如果应用层数据报超过了 64KB 我们有两种方式解决!
- 在应用层通过代码将应用层数据报进行手动分包,拆分成多个包,通过多个 UDP数据报 进行传输
- 不用 UDP协议 进行传输,换成 TCP协议 传输,因为TCP是面向字节流的,无长度限制
建议使用第二种方式,因为第一种需要写大量代码进行分包,从而增加我们的工作量
校验和:
- 网络传输的本质就是利用光信号或电信号所进行传播的
- 不排除会受到一些物理环境的影响导致出现 1变0 抑或是 0变1 的比特翻转情况
- 从而引入 校验和 来对数据内容进行校验,来验证数据是否传输出错
注意:
- 这里的 端口号 与 UDP 一样
- 这里的 校验和 与 UDP 一样
- TCP报文长度 = TCP报头 + TCP载荷
- TCP 报头长度是可变的,不像 UDP 固定为 8 个字节
- 因为 选项 表示对 TCP报文 的一些属性进行解释说明,这个可有可无
- 首都长度 描述TCP报头 具体多长
- 选项之前的部分(绿框部分)是固定长度为 20个字节
- 所以 首部长度 - 20字节 = 选项长度
- 此处的 首部长度 为 4 bit位,表示范围为 0~15
- 首部长度的单位为 4字节
- 如果首部长度数值为 5,表示整个 TCP 报头为 20 字节,此时没有 选项
- 如果首部长度数值为 10,表示整个 TCP 报头为 40 字节,此时 选项 长度为 20 字节
- 这里 保留位(6位) 是为 TCP协议 未来可能进行关键字扩展而所保留位置
- 通过 socket 拿到 outputstream,再将应用层协议格式的字符串 write 为 TCP载荷
确认应答
通俗解释:
- 指 发送方在发送数据后等待接收方发送确认消息,以确保消息已经被正确接收
- TCP将每个字节的数据进行了编号,也就是序列号
超时重传
通俗解释:
- 指在规定的时间阈值内没有收到对应的 确认ACK 或 响应 ,发送方会认为数据包已丢失或损坏,并重新发送该数据包
注意:
- 如果是 ACK 丢失,那么将会导致 主机A 传输重复数据给 主机B
- 当然 TCP 对于这种重复数据,是能够进行去重的
- 因为 TCP 存在一个类似 接收缓冲区 的存储空间,为 接收方 操作系统内核的一段内存
- 主机B 的网卡接收数据,将其放入 主机B 的接收缓冲区中
- 后续程序使用 getInputStream 进行 read 操作,即从接收缓冲区中读取数据
- 接收缓冲区 会更具接收到的数据序号进行重排序,保证 read操作 读取的数据为有序的
- 这时便会根据数据的序号,来进行判重,如果序号重复,则后来的数据将被直接丢弃,保证 read 操作读取的数据一定不重复
当然如果连续重传达到一定次数时,就不会继续重传,而会认为网络出现故障,从而 TCP 将会断开重连,如果重连失败,则直接断开连接
总结:
- 可靠传输时 TCP 最核心的部分
- 确认应答为 TCP报文传输顺利的情况
- 超时重传为 TCP报文传输出错的情况
- 二者相互配合,保障了 TCP 的可靠性
连接管理(三次握手 四次挥手)
建立连接(三次握手)
基本知识:
建立连接一般为 双方互相向对方申请建立连接 和 双发互相回应对方,这样看是四次交互,但是 TCP 建立连接的过程将其中两个进行了合并,从而变为三次交互
之所以能够合并,是因为 主机B 发送 SYN 和 ACK 是同一时机的,是系统内核中完成的,应用程序无法感知,当 主机B 的系统内核 收到 SYN 之后,会立即发送 ACK 同时也会立即发送 SYN,从而能够合并发送
三次握手的意义:
- 让通信双方各自建立对对方的认同(保存对方的信息)
- 验证通信双方各自的发送能力和接收能力是否正常
- 检查当前网络情况是否通畅(建立连接的过程不传输任何业务数据)
- 同步双方的初始序列号,并在建立连接后基于这些序列号进行数据传输
- 在握手的过程中,双方协商一些重要的参数,如窗口大小(用于流量控制和拥塞控制)
断开连接(四次挥手)
基本知识:
- 四次挥手 是不能将 ACK 和 FIN 合并发送的!
- 因为 合并发送的前提是 处于同一时机,因为 ACK是由系统内核控制的,当 主机B 收到 FIN 时,会立即发送 ACK,而 FIN 是由应用程序所控制,仅当调用到 socket 的 close 方法 抑或 进程退出,才会触发 FIN 的发送,所以 ACK 和 FIN 的发送并不处在同一时机,而是会有一段时间差,从而不能合并发送
注意:
- 三次握手和四次挥手也会进行超时重传
- 面试的时候尽量画图来进行说明,不要口头描述!
滑动窗口
- 滑动窗口机制 的本质是 不等待的批量发送一组数据然后用一份时间来等待着一组数据的多个 ACK 从而降低了确认应答等待 ACK 消耗的时间
- 可靠性 和 传输效率 是相互矛盾的,而滑动窗口机制 仅是保证可靠性的基础上,尽量的提高传输效率
丢包问题:
- 快速重传 为 超时重传 的一种 特殊情况
- 如果当前传输数据密集,按照滑动窗口的方式来传输,此时按照 快速重传 来处理丢包,只重传丢失了的数据,而不会在 1001~2000 数据发生丢包之后,将 主机A 传输给 主机B 如 2001~7000 的数据再重新传一遍,因为该部分数据 主机B 是接收到了的!
- 如果当前传输数据稀疏,不按照滑动窗口的方式来传输,此时便按照之前的 超时重传 处理丢包
注意:
- 虽然窗口越大,传输效率就越高,但是窗口也不能无限大
- 窗口无限大,也就相当于完全不等待 ACK 了,此时不能保证 TCP 的可靠性
- 窗口过大,其所消耗的系统资源也会相应扩大
- 窗口过大,导致发送数据过快,接收方处理速度跟不上来,相当于白发
流量控制
- 一种干预发送窗口大小的机制
- 发送窗口大小不是固定值,而是随着传输过程的进行,动态调整的
拥塞控制
- 流量控制 和 拥塞控制 共同决定发送方的窗口大小(取二者的较小值)
- 流量控制 考虑 接收方 的 处理能力
- 拥塞控制 考虑 传输过程中 中间节点 的 处理能力
基本思路:
具体思路:
- 拥塞窗口不是固定数值,一直是动态变化的,随着时间的推移,逐渐达到平衡的过程
延时应答
- 基于 流量控制,引入提高效率的机制
具体思路:
- 窗口越大,网络吞吐量就越大,传输效率就越高,保证网络不拥塞的情况下尽量提高传输效率
理解示例:
- 接收缓冲区大小为 1M,一开始接收到 600K 的数据,如果立即返回的窗口大小则为 400K
- 但是如果 接收缓冲区 仅用 50ms 就将 600K 数据快速处理完毕,此时让 接收端 延迟一会再返回 ACK,则返回的窗口大小就变大为 1M
- 扩大了窗口的大小,从而提高了传输效率
捎带应答
- 基于 延迟应答,引入提高效率的机制
注意:
- 能够合并传输的前提是 此处的 ACK 与 业务相应 处于 同一时机 发送
- 延迟应答 将合并传输的概率提高
面向字节流
粘包问题
解决方案:
- 约定 分隔符号,如 使用 " ;" 作为数据报的结束标志
- 约定 每个包的长度,如 在数据包开头位置声明长度
TCP 中的异常处理
进程崩溃
- 相当于进程没有了,对应的系统会回收系统资源,包括释放文件描述符 表,相当于 执行了 socket 的 close 方法 ,在内核执行 四次挥手 操作,正常断开连接
主机关机
- 主机关机前需将 进程 删除,然后才正式关机,跟上述的进程崩溃的过程一样
主机掉电
- 接收方掉电:发送方仍继续发送数据,发完等待 ACK ,等不到 ACK,进行 超时重传,仍然接收不到 ACK,则重置 TCP 连接(复位报文段:RST),重置连接失败,放弃连接
- 发送方掉电:接收方等待接收数据,与此同时 接收方 会给 发送方 周期性地发送一个 心跳包 (该包不携带任何业务数据),以此来确认 通信双方 处在正常的工作状态之中,该机制称为 保活机制
网线断开
- 同上述主机掉电
对比 TCP 和 UDP
- TCP 适合对可靠性有要求的场景
- UDP 适合对可靠性要求不高 且 对传输效率要求高的场景(如 机房内网传输,对传输效率要求高,其本身不易丢包)
如何使用 UDP 实现可靠传输
思路:
- 考察 TCP 保证可靠性的几大核心机制
具体答法:
- 引入序列号 保障 数据顺序
- 引入确认应答,保障 接收端 接收到了数据
- 引入超时重传,保障 数据未被接收 仍能重新传输丢失数据
- 等等