一、传输层协议

在开始 ”传输层协议“ 之前先简单介绍在应用层里面 “自定义应用层协议” :

自定义应用层协议有两个要点:交互时传递的信息有哪些;信息的组织方式是什么。

而传输方式一般包含以下几种:固定格式数据约定格式XML格式json格式二进制数据组织格式(protobuffer以及thrift)。XML与json是一种文本格式(可读性高但占用带宽高、效率低),protobuffer与thrift格式复杂(占用带宽低、效率高但可读性差)

接下来介绍传输层里的两个重要协议: TCP 和 UDP

1.1、UDP协议

传输层协议UDP&TCP_TCP协议

在上述图中是一个大致的UDP数据报,可以看出UDP数据报为8个字节;其中 “目的端口号” 是用来识别应用程序的位置:使用IP地址可以区分出不同的主机,而主机里面不同的应用程序就靠端口号来区分。而 ”UDP长度“ 就表示UDP数据报有多长,因此可以明显的看出2字节大小放在现如今是完全不够用的。

因此在现实应用中会用 TCP 来代替。(TCP没有长度限制)

什么是“校验和”???

网络传输的过程中,由于数据大,传输的数据不一定是准确无误的(网络信号会受到干扰)在使用 UDP 传输数据的时候,对于要传送的数据就会计算一个“校验和” 数据发送的时候就会将 “校验和” 一并发送过去。接收数据时,就会针对接收到的数据也计算一个 “校验和” ,两个 “校验和” 之间进行比较:如果一致,数据就没问题,否则数据就有问题。

而对于 UDP 计算 “校验和” 一般使用的是简单的 CRC 算法( 循环冗余校验和 ),传入的数据相同的话,“校验和” 一定相同;但是 “校验和” 相同,传输的数据不一定相同。

2.2、TCP协议

对于 TCP协议 :有连接,可靠传输,面向字节流,全双工;而 可靠传输 则是TCP协议 的核心。

什么是 “可靠传输” ???

言简意赅的说就是当信息发送出去之后,发送方可以知道接收方有没有收到信息。例如:张三打电话给李四,张三作为发送方可以清楚的知道李四有没有接电话,如果接电话,信息传送给李四。如果没接电话,信息没有传送给李四。

“可靠性传输” 如何保证???

传输层协议UDP&TCP_UDP协议_02

在 “后发先至” 的情况下,无法通过顺序来判断当前的 应答报文 是在应答哪个数据。因此就会做出如下改进:::

传输层协议UDP&TCP_UDP协议_03

2.2.1、确认应答

传输层协议UDP&TCP_UDP协议_04

如何区分 “普通报文” 和 “应答报文”

传输层协议UDP&TCP_TCP协议_05

如何理解“UDP面向数据报,TCP面向字节流”???

传输层协议UDP&TCP_UDP协议_06

2.2.2、超时重传

如何解决发送方没有收到 ACK 的情况???

在确认应答时,如果网络拥堵,就可能导致 丢包,任何一个数据报都可能会丢失,而此时如果 ACK 没有收到就会导致 超时重传 :发送方等待一定时间后如果没有收到ACK就会重传数据。而这丢包又分为两种情况:

  • 发送方发送数据过程中,网络拥堵导致丢包;
  • 接收方收到数据返回ACK时网络拥堵导致丢包;

上述两种情况都会使发送方重新发送数据给接收方,但是第二种情况下就会使接收方收到两份相同的来自发送方的数据(当一定时间后发送方没有收到 ACK 就会重新发送数据给接收方),此时接收方就要根据 序号 来对数据进行去重,以保证数据不会重复。上面的这种机制就叫做 “超时重传”。

但是 超时重传 也不是无限制的重复重传,尝试几次后仍然无法传输就会断开连接重连,如果此时依然无法连接就会彻底放弃。

2.2.3、连接管理

在 TCP 里面有 建立连接 与 断开连接 ;而 建立连接 需要经历 “三次握手”,而且 客户端 是主动的一方 ,握手也是有 客户端 发起的。

传输层协议UDP&TCP_TCP协议_07

三次握手 的意义是什么???为什么是 “三次”???

三次握手 也是一种 保证可靠性 的一种机制。这种机制就类似于为程序的后续运行提供的一种保障,确保通信双方的接收/发送功能正常,同时在此过程中也会处理一些参数。

传输层协议UDP&TCP_TCP协议_08

“四次挥手”:断开连接

传输层协议UDP&TCP_TCP协议_09

服务器与客户端的几种状态:

传输层协议UDP&TCP_TCP协议_10

2.2.4、滑动窗口

在程序运行的时候,不仅要考虑 可靠性 还要考虑 效率 的问题。但是在程序里面 可靠性 和 效率 是互相影响的,如果想要保证 可靠性 ,那么 效率 就会受到影响,对于 TCP 我们要保证 可靠性 的前提下提高 效率。

而 滑动窗口 就是TCP提高效率的一种机制。其本质就是把等待ACK的时间叠加起来,而减少了等待时间就相当于提高了效率。

传输层协议UDP&TCP_UDP协议_11

但是这里的窗口并不是越大效率就越高,对于传输效率来说,其大小取决于发送效率与读取效率的综合。对于 滑动窗口 来说需要考虑 丢包 的问题:

  • 收到数据报,ACK丢失
  • 数据报丢失

对于第一种情况来说:如果在滑动窗口传输的数据是:1-1000、1001-2000、2001、3001-4000时,如果此时丢失的是1-1000返回的 ACK,但是由于在1000后面的数据是正常接收的,所有会返回 ACK,此时会有一种 涵盖 的效应,也就是说 后一个数据的ACK会涵盖前面数据的ACK,此处即使没有返回ACK也没有很大的影响。

对于第二种情况来说:如果滑动窗口传输的数据是:1-1000、1001-2000、2001、3001-4000时,如果此时丢失的数据是1-1000,如下图

传输层协议UDP&TCP_TCP协议_12

此处当客户端发现重复返回“从1001开始”时,客户端就会自动将丢失的数据传输,而已经传输的数据(1001-2000、2001-3000)就不会再重复传输,这也是一种 快速重传 机制。滑动窗口 在一定程度上是可以提高效率的,但是与 无可靠传输的UDP 相比,效率 还是慢一些的。

2.2.5、流量控制

对于上面讲到的 滑动窗口 来说:窗口越大,意味着发送的速率就快,而发送的快并不代表接收的速率快。相反,如果 发送速率 远大于 接收速率 ,此时 整体的速率 依然是不够快的,反而会因为接收方丢包触发重传,降低速率。因此,流量控制 要实现的就是 发送速率 和 接收速率 相当。

在操作体系中,会为接收方提供一个 接收缓冲区 ,从发送方接收到的数据会先放在这个缓冲区里面,接收方就会从缓冲区里面读取数据,而读取数据的快慢就是刚才所说的 接收速率。而 流量控制 就是通过接收缓冲区剩余空间的大小作为下一次发送数据时窗口的大小。

在 TCP 报头里面有一个 “16位窗口大小” 字段:如果当前是 ACK报文 ,此时就会生效,这个窗口的大小就表示了接收缓冲区剩余空间大小,根据这个大小,就会进一步的影响发送速率。如果此时接收缓冲区满了,此时窗口大小就会变成 0,此时就会暂停,过一段时间后会场时发送一个 “窗口探测包”,通过“窗口探测包”  并返回一个窗口更新的通知。

2.2.6、拥塞控制

在传输数据的同时,接收方与发送方中间的设备对速率也有着极大的影响,而 拥塞控制 就是通过做实验的方法找到一个最合适的窗口大小:

在程序刚开始时会按照小窗口进行传输,如果此时没有发生丢包,说明中间的设备运行良好,此时就会逐渐的增加窗口的大小;当增加到一定程度时,速率变快,网络就会出现拥堵,此时可能会导致丢包,当发生丢包时,此时就要减小窗口的大小。由此在增大窗口与减小窗口之间来回循环,达到“动态平衡”

流量控制 和 拥塞控制 都能控制窗口的大小,从而制约发送方的传输速率,而最终的滑动窗口的大小则取决于两者之间的较小值。

2.2.7、延时应答

在上述内容中我们知道:在数据发送与接收的过程中,滑动窗口的大小会影响到数据的传输,如果接收数据的主机一接收到数据就立刻返回一个滑动窗口的大小,此时由于时间较短,数据量大,就会导致缓冲区内的数据无法被完全接收,就会导致滑动窗口小。那么如果让返回滑动窗口的等待时间变长一些,此时缓冲区的数据就有足够的时间来接收,这样一来就会提高数据的传输效率。

2.2.8、捎带应答

在“四次挥手”的时候,我们知道当发送端发送 FIN 之后,接收端会立即返回一个 ACK ,再等待一段时间后,接收端会再返回一个 FIN ,发送端接收之后就会返回一个 ACK。而在 捎带应答 的机制下,接收端并不会立即返回 ACK,而是等待与接收端的 FIN 一起传输给 发送端。

2.2.9、面向字节流

在前面我们说过 “面向字节流” 和 “面向数据报” 的区别。但是面向数据流会遇到一个问题:如何将数据流根据不同的数据报进行区分呢?“面向数据流” 最核心的一个问题就是 “粘包问题” 。

如果说一个TCP连接里面只传一个数据报,此时就不用考虑 “粘包问题”(短连接);但是如果说一个TCP连接里面传多个数据包,此时就要考虑如何区分不同数据报的数据。为了解决这个问题,我们就需要对传过来的数据包明确他们之间的边界:(自定义应用层协议)

  • 使用分隔符分隔;
  • 固定每个字节流长度;

通过这两种方式就可以明确区分出一个完整的数据报。

2.2.10、TCP异常处理

  • 主机关机
  • 程序崩溃
  • 主机掉电
  • 网线断开

主机关机:按照程序关机,会杀死所有的用户进程(包括自己写的TCP进程),并释放进程的PCB,释放文件描述符表上的对应内容,并触发“四次挥手”,如果挥手完成就继续关机;如果还没完成挥手,就会重传FIN,多次尝试依然没有响应就会自动放弃。

程序崩溃:同上。

主机掉电:如果是接收方掉电,对方会尝试重新发送数据——>没有ACK返回——>尝试从新建立连接——>建立失败。此时就会认为网络出现问题,自动放弃。如果是发送方掉电,在这种情况下,接收方在等待发送方数据的时候,不会知道发送方是因为还没有发送数据,或者发送方出现问题:此时接收方如果一段时间没有收到数据就会定期给发送方发送“心跳包”:接收方发送一个特殊的报文(ping),发送方会返回一个报文(pong)。如果这个过程交互成功,就认为对方状态正常;如果没有收到回复,就认为发送方已经挂了。

网线断开:同上。

TCP和UDP对比:

注重可靠性传输、传输的单个数据报较大:优先考虑TCP;

注重高性能、广播式传输(一个发送方,多个接收方):UDP