# TCP&UDP


# TCP/UDP

# ***传输层***

## ***传输层的定义***

- *传输层是第一次在端对端也就是主机对主机的一层 专门负责处理上层的数据 负责可靠不可靠的传输*
- *传输层下层是使用 mac 和 ip 地址来寻找到特定主机 但是光凭 mac ip 可不够,还要需要端口, 也是在这一层 有了端口的概念*
- *这一层的数据单位称为数据段*

# ***TCP***

## ***TCP 概念 & 流控制***

- *TCP是 **面向有链接** 协议, 因为他是 **流控制**，也被称作流式协议*
- ***流控制：** 接收端告诉发送端 我这边可以接收多少数据 发送端也跟接收端确认少数据 取最小值 将数据切割*
- *TCP是可靠协议 他有一系列的方法来实现可靠性*

## ***TCP 序列号 & 应答机制***

1. **引出：**
   - *TCP是一个可靠协议 所以TCP需要各种方法来保证他的可靠性*
2. **解决：**
   - *发送端发送数据后 接收端接收成功 会发送一个**ACK应答***
   - **缺点**
     - *万一ACK发送失败 发送端就会一直发送数据 这是一个问题*
3. **优化：**
   - *引入 **序列号** 机制 为每一个数据都打上一个序列号 ACK也算一个序列号*
   - *接收端收到数据后, 就会分析她下一次应该接收数据的序列号 然后以ACK应答出去*

## ***TCP 重发超时***

1. ***RTT 与 RTO***
   
   - **RTT 和 RTO的概念**
     
     - *TCP作为一个面向有连接型的协议，需要保证其可靠性 所以其内部实现了一个重传计时器*
     - *每发送一个数据包，就给这个数据设置一个重传计时器, 如果在计时器超时之前收到了针对这个数据包的ack，就取消这个计时器。如果没有收到，则开始发起重传。计时器超时的时间被称为RTO，这个时间的确定取决于RTT*
- **关于两者详细的解释**
  
  - `RTT(Round Trip Time)`: *一个连接的往返时间，即数据发送时刻到接收到确认的时刻的差值*
  - `RTO(Retransmission Time Out)`: *重传超时时间，即从数据发送时刻算起，超过这个时间便执行重传*
2. ***RTT的测量***
   
   - ***每发送一个分组 TCP就会对其采样，这个采样只会对同一时间的数据段进行采样, 随后用这个采样记录当作RTT***
   - **采样方法一般有两种**
     - ***采用时间戳：*** *发送一个数据段时在TCP选项中记录下时间 收到数据段再记录下时间 随后计算出差值 就把这个差值作为RTT 但是需要发送端和接收端都需要支持这个选项*
     - ***重传队列中数据包的TCP控制块：*** *每个数据包第一次发送出去后都会放到重传队列中，数据包中的TCP控制块包含着一个变量，tcp_skb_cb->when，记录了该数据包的第一次发送时间。如果没有时间戳选项，那么RTT就等于当前时间和when的差值*

3. ***RTO的计算***
   
   - ***为了避免单次RTT波动，计算RTO时新引入了变量SRTT，表示更加平滑的RTT数值，它的计算方法：***
   
   ```cpp
   SRTT = x(SRTT) + (1 - x)RTT;
   // x被称为平滑因子，一般建议设置在[0.8, 0.9]，意思是SRTT值百分之八十来自于之前的值，百分之二十来自于当前值。
   ```
   
   - ***计算RTO的方法为：***
   
   ```cpp
   RTO = min(ubound, max(lbound, y(SRTT)));
   // y 是时延离散因子，推荐值为[1.3, 2.0]，ubound是RTO的上边界，lbound是RTO的下边界
   ```

4. ***算法的缺点***
   
   - *在RTT波动较大时，RTO不能明显适应网络变化*

5. ***标准方法***
   
   1. *标准方法引入了**平均偏差**的概念，它类似于统计学里面的方差，但是因为方差的计算过程代价较大，对于快速TCP来说不太适合。假设rtt的值为M，RTO的计算方式为：*
   
   ```go
   srtt = (1 - g)srtt + g(M);
   rttval = (1 - h)rttval + h(|M - rttval|);
   RTO = srtt + 4(rttval);
   /*    
       其中`g`设置为1/8，`h`设置为`1/4`
       对srtt而言，它有1/8取决于当前值，7/8取决于现有值    当RTT变化时，偏差增量越大，RTO的增量也越大
   */
   ```

## ***TCP 三次握手***

1. ***第一次握手***
   - ***SYN = 1，seq = x***
   - *客户端发送一个 **SYN标志为1**，指明客户端打算连接的服务器**端口**，以及初始的**序列号为随机生成的 x** 的一个TCP包*
   - *发送完成后，客户端进入 `SYN_SEND`状态*
2. ***第二次握手***
   - ***SYN = 1，ACK = 1，seq = y，ACKNum = x+1***
   - *服务端发回 SYN=1 ACK=1，并且ACK也算一个序列号+1 所以ACKNum是 x+1，随后再把自己要发送的数据标上序列号，序列号变成了 y 的一个TCP包*
   - ***服务端发送完毕后 进入 `SYN_RECV`状态***
3. ***第三次握手***
   - ***ACK = 1，ACKNum = y+1***
   - *客户端再次发送确认包(ACK)，SYN 标志位为0，ACK 标志位为1，并且把服务器发来 ACK 的序号字段+1，放在确定字段中发送给对方，并且在数据段放写ISN的+1*
   - ***发送完毕 客户端进入 `ESTABLISH`状态，服务端接收到这个包后 也进入`ESTABLISH`状态，TCP握手结束***

## ***TCP 四次挥手***

1. ***第一次挥手***
   - ***FIN = 1, seq = x***
   - *假设客户端想要关闭连接，客户端发送一个FIN标志位置为1的包，表示自己像断开连接 没有数据可以发送了，但是仍然可以接收数据*
   - *发送完毕后，客户端进入 `FIN_WAIT_1` 状态*
2. ***第二次挥手***
   - ***ACK = 1 ACKNum = x + 1***
   - *服务端接受到了客户端想要断开的链接的请求，便发出了一个ACK标志位为1的TCP包，表明自己接收到了请求，但还没有准备好关闭连接*
   - *发送完毕后，服务器端进入 `CLOSE_WAIT` 状态，客户端接收到了这个确认包之后，进入 `FIN_WAIT_2`的状态，等待服务端关闭连接*
3. ***第三次挥手***
   - ***FIN=1，seq=y***
   - *服务器端准备好关闭连接时，向客户端发送结束连接请求，FIN 置为1*
   - ***发送完毕后，服务器端进入 `LAST_ACK` 状态，等待来自客户端的最后一个ACK***
4. ***第四次挥手***
   - ***ACK = 1，ACKNum = y + 1***
   - *客户端接收到来自服务器端的关闭请求，发送一个确认包*
   - ***客户端发送完包并进入 `TIME_WAIT` 状态，等待可能出现的要求重传的ACK包***
   - ***服务端接收到这个确认包后，关闭连接，进入`CLOSED`状态***

## ***为什么需要3次握手 挥手需要4次***

1. ***3次握手目的是要确定客户端和服务端通信也就是两边的“收”“发”功能是否正常***
   - *第一次握手: 客户端发送网络包 服务器收到了 这个时候服务端就能确定客户端的"发" 和 服务端的 "收" 都没有问题*
   - *第二次握手: 服务端发送 这个时候客户端就能确定 客户端的 "发收" 服务端的 "收发" 是没有问题的 但是服务端还没有确定*
   - *第三次握手: 客户端发包 这个时候服务端就能确定 服务端的 "发收" 客户端的 "收发" 是没有的问题的*
   - ***所以综上所述 两次握手是没有办法确定 双方的通信能力是否正常 至少也要三次***
2. ***4次挥手目的是要数据接收完毕 不能在数据没有接受完全就直接关闭了连接TCP连接是双向传输的对等的模式, 就是说双方都可以同时向对方发送或接受数据***
   - *第一次挥手: 当有一方要关闭连接时，会发送指令告知对方 我们要close连接*
   - *第二次挥手: 对方回一个ack应答 此时一个方向的连接关闭 但是！另一个方向仍然可以继续传输数据 等到数据发送完 就进行第三次挥手*
   - *第三次挥手: 发送FIN段*
   - *第四次挥手: 回ACK应答*

## ***TCP 以段为单位发送数据***

1. ***什么是段***
   - *在三次握手的期间发送端会告诉接受端 我一次性能发送多少数据接受端也会告诉发送端 我一次性能接受多少数据随后发送端就会把全部数据切割为最小值 发送出去*
   - *这个最小值为段*

## ***TCP 窗口控制***

1. ***引出***
   - *当我们以段为单位 一次发送数据 随后又得等待ack 这样包的往返效率很慢*
   - *所以tcp采用了滑动窗口来优化*
2. ***什么是窗口控制***
   - *滑动窗口就是我们设置窗口值 在没超够窗口值的前提下 不用等待ack的应答 就可以发送段数据*

## ***TCP 重发控制***

1. ***引出***
   - *当我们利用窗口来发送数据 如果有数据丢失怎么办*
2. ***ACK丢失***
   - *如有几个ack应答丢失是没有关系的 因为剩下的ack会到达发送端*
   - *所以一对比单个段发送的效率 窗口的性能还是蛮高的*
3. ***段丢失***
   - *如果段数据丢失了 接受端会一直返回相对应的序列号的ack应答 如果发送端一直接受同样的ack三次 就会进行重发*

## ***TCP 拥塞窗口***

1. ***引出***
   
   - *计算机网络都处在一个共享的环境。 因此也有可能会因为其他主机之间的通信会造成网络拥堵。如果在网络拥堵的时候 发送一个较大量的数据包 会可能导致整个网络的瘫痪*

2. ***什么是拥塞窗口***
   
   - ***TCP在通信一开始的时候会通过一个叫做慢启动的算法得出的数值，对发送数据量进行控制***
   - *首先，为了在发送端调节要发送数据的量,定义了一个叫做 “拥塞窗口” 的概念    在慢启动的时候，将这个窗口调节为1个数据段发送数据，随后没收到一个ack就进行+=1    在发送数据的时候 也会将其拥塞窗口的大小和接受端的窗口对比 取其最小值 然后发送比这个最小值还小一点的数据*

3. ***上述解决办法会出现的问题***
   
   - *随着包的往返，拥塞窗口也会以 1 2 4 等指数函数增长，拥堵状况激增甚至导致拥塞的发生*
   - ***慢启动阈值他也就来了***

4. ***慢启动阈值***
   
   - *只要拥塞窗口的值超过这个范围，则每一次收到ack，只允许下面这种比例放大拥塞窗口*
   
   - ```cpp
     1个数据段的字节数 / 拥塞窗口(字节) X 1个数据段字节数
     ```

## ***TCP 连接状态***

- ***CLOSED: 初始状态***
- ***LISTEN: 服务器处于监听状态***
- ***SYN_SEND: 客户端socket执行CONNECT连接，发送syn包 进入此状态***
- ***SYN_RECV: 服务端收到SYN包并发送服务端SYN包，进入此状态***
- ***ESTABLISH: 表示连接建立。客户端发送了最后一个ACK包后进入此状态，服务端接 收到ACK包后进入此状态***
- ***FIN_WAIT_1: 终止连接的一方发送了FIN报文后进入,等待对方FIN***
- ***CLOSE_WAIT: 假设服务器)接收到客户机FIN包之后等待关闭的阶段。在接收到 对方的FIN包之后，自然是需要立即回复ACK包的，表示已经知道断开请求。但是本 方是否立即断开连接(发送FIN包)取决于是否还有数据需要发送给客户端，若有， 则在发送FIN包之前均为此状态***
- ***FIN_WAIT_2: 此时是半连接状态, 既有一方要求关闭连接，等待另一方关闭，客户端接收到服务端的ACK包，但并没有接收到服务端的FIN包，进入FIN_WAIT_2状态***
- ***LAST_ACK: 服务端发动最后的FIN包，等待最后的客户端ACK响应，进入此状态。***
- ***TIME_WAIT: 客户端收到服务端的FIN包，并立即发出ACK包做最后的确认，在此之 后的2MSL时间称为TIME_WAIT状态。***

## ***TCP 首部格式***

1. ***源端口号***
   - *发送方的应用端口 占16位*
2. ***目标端口号***
   - *接受端的应用端口 占16位*
3. ***序列号***
   - *占32位*
   - *发送端会在发送数据的每个字节上标上序号*
   - *不一定每一个序列号都是0, 1开始的 这个序列号是随机的 会在syn包也就是第一次握手 告诉接受端*
   - *syn包 & fin包 & ACK 都是一个字节*
4. ***确认应答号***
   - *占32位*
   - *收到数据后 会返回下一次应该收到的序列号信息作为确认应答*
   - *这个确认应答也就代表着 前面的数据我都收到了的意思*
5. ***偏移量***
   - *tcp首部长度*
6. ***保留***
   - *占4位 主要是为了以后扩展用的 一般都是0*
7. ***控制位***
   - *字段长为8位, 当它们对应位上的值为1 就会有特殊作用*
   - ***三次握手, 四次挥手***
     - *ack 该位为1时, 确认应答的字段变为有效, tcp规定除了最开始的syn包外, 必须为1*
     - *syn 该位为1时, 代表希望建立连接, 并且序列号会随机生成*
     - *fin 该位为1时, 代表希望断开连接*
   - ***英语全称(其实一开始作者看错了 以为都是p开头 结果阴差阳错发现了 然后就记住了 哈哈) =-=***
     - *psh(push) 该位为1时，代表需要直接将数据传给上一层 / 该位为0时 需要先进行缓存在进行传送*
     - *rst(reset) 该位为1时，代表tcp连接出现异常 必须强制断开连接 比如对方突然断电*
   - ***紧急指针相关***
     - *URG 该位为1时，代表包中有需要紧急处理的数据*
   - ***拥塞窗口***
     - *cwr 该位为1时，则会通知对方拥塞窗口缩小*
     - *ece 该位为1时，通知对方，从对方到这里的网络有拥塞*
8. ***窗口大小***
   - *长为16位*
   - *代表发送数据最多不能超过这个窗口大小*
   - *如果窗口大小为0 则就是代表可以窗口探测 去寻找最新的窗口大小*
9. ***校验和***
10. ***紧急指针***
    - *该字段长为16位, 只有在URG控制位为1时有效*
    - *数据的首位到紧急指针指向的位置 都是紧急数据*
    - *怎么处理紧急数据 就是应用层要实现的事情, 一般在暂停通信 或者中断通信的时候使用*
11. ***选项***

# ***UDP***

## ***UDP 概念 & 用途***

1. ***UDP 是面向无连接协议 爆式协议 他不会去管数据到底有没有到达 所以想啥时候发数据就啥时候发数据经常用于广播 视频 音频等***

## ***UDP 首部格式***

1. ***因为UDP简单 所以首部只有 源端口号 目标端口号 检验和 包长度 四个数据***

