TCP/UDP协议详解
TCP协议和UDP都是传输层的重要协议,负责数据能够从发送端传输到接收端。
TCP协议(可靠传输)
四位头部长度 指的是:TCP报文的长度 【此处的单位是4字节==》如果此处长度为 1111(15) 实际长度就为 15*4=60字节】
保留的六位 是为了以后的长度升级留点空间
六个标志位是 TCP 报文中的核心字段
32位序号 和 32位确认序号 与确认应答机制有关
-
确认应答机制 确认应答机制的关键在于:接收方在收到数据后,会向发送方回复一个类似与“收到”的消息【ACK】 但是如果发送方同时发送多个数据,就可能有如下情况(后发的消息先到达) 上述就会导致消息传输上产生误差,所以需要引入 序号 (每句话对应一个序号 就不会出错) 这就是TCP报头中的 序号 和 确认序号 ,TCP中的序号与确认序号是按照字节进行编号的 但是当传输过程中出现丢包时,不能正确返回ACK,发送方就不能发送接下来的数据,所以可能触发 超时重传
-
超时重传 当数据在传输过程中丢包时,会触发 超时重传——在一定时间内没有收到ACK,发送方就会重新传一次数据
但是如果是ACK丢了,发送方就会发送两次数据(但是TCP内部自动去重),就不会导致接收方收到两次重复的消息了
当网络遭受严重伤害时,发送方重传多次都没有收到ACK,发送方就会放弃重传,自动断开TCP的连接
-
连接管理【三次握手、四次挥手】重点 面试必问 客户端与服务器如何建立连接?——三次握手
客户端和服务器经过 三次交互,建立连接 ,在三次握手没问题的前提下,就可以确定当前网络满足可靠传输的基本条件
有图可以看出将接收方的ACK和SYN封装为一次发送,更为的高效一些
提问: 为什么要三次握手?两次不行吗?四次不行吗?
两次不行 !!! 三次握手是在检查进行通信的双方,发送能力和接收能力是否都正常。
四次行 但没必要 将一些消息合并,是传输更加高效不好吗?
经历了上述的三次交互过程,就能确定通信双方的 发送能力 和 接收能力 都良好,具备可靠传输的前提,能建立连接。 当客户端与服务器建立连接后,就需要用一定的数据结构来保存连接的相关消息(源IP、源端口号、目的IP、目的端口号、协议类型) 客户端与服务器如何断开连接?——四次挥手
客户端和服务器要断开连接,就需要释放掉内存保存的连接信息。
四次握手 可以是客户端发起的,也可以是服务器发起的。
四次挥手中,2,3发送的时机不一样,所以一般不能合并,如果两个发送的时间相差很少,就可以合并。
必须四次挥手都完成后,双方才能断开连接。
第三次挥手后,客户端将ACK发送完成后,就会立即断开连接吗?
不行,如果这样,假设这个ACK丢包了,及聚会触发服务器的超时重传,服务器重新发送FIN就无人应答,所以客户端得等一段时间, 这个等待的状态就叫做:TIME_WAIT.在确保服务器不会重传了之后,再真正的断开连接。这个等待时间就是**(2*MSL)**
MSL : 网络上的任意两点之间,传输所需的最大时间,一般设为60s。
-
滑动窗口【保证可靠性的前提下提高传输效率】 由于确认应答机制的存在,发送方在每一次发送完数据后,都会等待接收方的ACK(导致大量的时间花费在等待ACK上) 为了保证传输效率,所以一次可以发送一波数据 上图中,一次发送四组数据,然后统一等待ACK,就将等待ACK的时间压缩了。 当发送方收到第一组ACK时,就继续发送下一组(4001-5000)的数据,此时ACK的范围就变化(2001、3001、4001、5001),后面同理。 窗口越大,传输效率越高窗口越大,一份时间里就可以等待更多的ACK,总的等待时间更少。 但是如果滑动窗口下丢包了,怎么处理呢?【快速重传】
-
假设ACK丢了 **没有问题,直接继续发送,**当收到“下一个时2001”的ACK时,说明2001之前的数据已经全部收到,所以没有1001的ACK已经无所谓了。 -
假设数据丢了 当没有收到数据(假设1001-2000),接收方就会一直索要1001-2000的数据 当发送方连续三次收到这样的ACK时,就会触发重传 同理,如果中途有其他数据丢包,接收方也会反复向发送方索要该数据,直到收到重传的数据。 -
流量控制【滑动窗口的延伸 限制滑动窗口发送的速率】
-
在滑动窗口中,窗口越大,传输的效率就越高,但是 还需要考虑接收方的接收能力 如上图所示,如果发送方发的太快太多,填满缓冲区后,还源源不断得到发送数据,接收方来不及接收数据,就会直接丢包 -
滑动窗口中,发送方会根据接收方的接收能力调整发送的速度
- 接收能力越强,处理数据就越快,缓冲区剩余空间就越多
- 接收能力越弱,处理数据就越慢,缓冲区剩余空间就越少
-
根据缓冲区剩余空间大小来衡量接收效率
-
发送方怎么知道缓冲区的剩余空间大小呢?——根据ACK报文进行传输 -
当发送方收到的ACK报文中缓存区的剩余空间为0时,就先不发送数据,定期 发送一个探测报文(心跳包),触发接收方发送ACK,待对方的缓冲区有空间时,再发送数据。 -
拥塞控制【滑动窗口的延伸 限制滑动窗口发送的速率】
- 拥塞控制指的是发送方和接收方中间的中间链路的处理能力
因为中间链路的设备多,且不能准确知道其处理能力,所以需要通过不断地实验(不断调整发送速度)测得一个最合适的发送速度
- 每次出现丢包后,会根据网络的拥堵情况更新阈值,最理想的发送窗口应该位于阈值和丢包之间
-
延时应答【流量控制的延伸 尽量使接收缓冲区剩余空间更大】
- 每次往水池注水时,都会询问出水方 :当前水池的剩余空间大小, 出水方会返回一个空间大小给注水方
- 延时应答就是 出水方 不立即返回, 而是等一段时间(延时应答时间),在这段时间里,出水方又多放一些水,所以回复的剩余空间比之前可以更大一些
- 在有限的情况下,又尽可能的提高了一点速度
-
捎带应答【延时应答的延伸】 因为 延时应答的存在,ACK的回复会更慢,所以当和响应同时发送时,就会合并为一次发送,提高了传输的效率 -
粘包问题【面向字节流】
-
粘包问题指的是: 应用层数据包 在TCP接收缓冲区中,数据包混合在一起,分不出来谁是一个完整的数据包(数据包会在到达接收方后进行分用,将TCP报头去掉,将里面的数据取出来,放入缓冲区) -
假设数据在分用后不做任何处理,直接放入缓冲区,那么取的时候就不知道谁是谁了 -
解决方案: 在应用层协议中加入包与包之间的边界(例如包与包之间加入 ;)---->【自定义应用层协议,有几个典型的实现:1. xml 分隔符就相当于结束标签;2. json 分隔符就相当于 } ;3. protobuffer 里面通过声明长度分隔;4. http 分隔符和长度都会用到】
- TCP中的异常处理
相当于进程的异常退出,操作系统会回收进程的资源——包括 释放文件描述符表。这样的释放操作就相当于调用了对应的socket的close socket.close 。执行close就会触发FIN报文,进一步的就是开始四次挥手。
这种情况和普通的四次挥手没啥区别
在关机前,会让操作系统杀死所有进程,本质上与进程终止一样
-
机器掉电、掉网 如果接收方断电、掉网 如果发送方断电、掉网
UDP协议(不可靠传输)
UDP报头一共八个字节 可以看到,因为UDP报文长度为16位两个字节 所以UDP数据报单次最多只能传输64k的数据,这也是UDP使用过程的一个致命的缺陷。
源端口: 操作系统给客户端分配的端口
目的端口:服务器端口
校验和:验证通过网络传输收到的数据是否正确
- 基于个数校验
- 基于数据内容校验
TCP 和 UDP 之间的对比
TCP可靠性要求高
UDP 可靠性要求不高,同时对于传输效率要求很高使用UDP
|