文章目录
TCP协议
序列号seq和确认序号ack
seq是发送方将要发送的数据包的第一个序号,ack是期待对方发送的数据包的第一个序号
为什么需要seq和ack
因为TCP是传输层的协议,具有数据可靠传输的机制,因此需要发送方和接收方相互应答,所以诞生了seq用于回答对方的请求(发送对方需要的包)和ack用于请求对方的应答(告诉对方已经接受到了前面的包,可以发的下一个序号对应的包)
如何使用seq和ack
举个栗子:假设数据长度为1的情况下,当前A发送seq = 50,ack = 37的TCP报文给接收方,B收到后就会知道当前B收到了A发送的seq = 50的packet(包),期待B发送序列号(ack) = 37的packet给A,然后B会发送seq = 37、ack = 51的TCP报文给A
超时重传时间
- 超时重传是指当发送方发送packet后一段时间未收到接收方的确认应答,超过该时间限制就会重新发送packet给接收方
- 往返时间RTT(Round Trip Time):指发送方从发送packet到接收方,接收方发送packet重新回到发送方所经历的时间
- 当在互传时出现丢包的情况时需要重传丢失的包,超时重传时间 = RTT + 偏差(考虑网络拥塞情况)
3次握手和4次挥手
3次握手流程图
SYN和ACK
- SYN是建立连接的同步标志位,当需要建立连接时需要令SYN等于1(因为第三次握手其实已经处于半连接状态,只需要再次确认即可,因此无需SYN等于1,而且第三次握手报文可携带数据包,而第一次和第二次握手报文不能携带数据)
- 请着重区分ack和ACK,ACK为确认应答,即告诉对方我已经收到了该报文,而ack是告诉对方我期待收到的下一个TCP报文序列号
握手细节
- 首先发送方(即客户端)发送建立连接请求TCP报文,该报文的TCP首部中的SYN = 1,以及消耗一个序列号x,该报文不能携带数据;
- 当接收方(即服务端)收到建立连接请求TCP报文后,发送建立连接的TCP确认报文,该报文的TCP首部中的SYN = 1,确认应答ACK = 1,以及消耗自身的序列号seq = y,期待对方发送的包的下一个序列号为ack = x + 1,该报文不能携带数据;
- 最后进行第三报文握手,这个报文最主要是用于连接确认,该TCP包可携带数据,发送方(即客户端)会发送ACK = 1,序列号seq = x+1满足上一个接收方(即服务端)发送报文ack = x + 1的请求,同时请求期待下一个收到的包序列号为ack = y + 1
为什么需要3次握手?
3次握手是为了防止已经失效的连接请求报文又重新发给了接收方(即服务端),如果不进行确认就认为建立了连接,那么会导致接收方一直保持该无效的连接,造成资源的浪费
WireShark眼见为实
当我访问打开WireShark进行抓包的同时进行www.baidu.com网站访问时会建立3次握手,结果如下
我们观察上图前3行,可以看出在访问www.baidu.com网站时首先会进行3次握手建立连接,最主要关注上图右边的SYN、ACK、Seq、ack即可,上图将ack写成了Ack,但是不妨碍我们的理解
MTU和TCP首部中的MSS
MTU(Maximum Transmission Unit)为IP包(即网络层的IP数据包)的最大传输单位,大于MTU的IP包会被分片,默认MTU为1500字节,除去最小IP首部的20字节外,上层协议交付下来的TCP包最大为1480字节,如果TCP首部为最小的20字节,那么MSS(Maximum Segment Size)代表着不被分片的最大数据单元,即1500 - 20 - 20 = 1460字节
- 如图1,为了包的完整性,将MAC首部也一并添加进该图,在进行3次握手时为了避免分片问题;
- TCP双方会交换MSS,然后取最小的MSS作为双方传输的最大传输单位;
- 图2第一列是包序号,如上图所示:首先发送方发送序列号1408的包,该包MMS为1460,而接收方发送序列号1417的包,该包的MMS为1400,因此最大传输单元为1400个字节,请看序列号1447的包,发送方发送了Len = 1400个字节的包,由此验证了Min{发送方(MSS),接收方(MMS)}
4次挥手
WireShark验证4次挥手
挥手细节
- 因为TCP为全双工的网络协议,因此可以允许任意一方先断开连接;
- 假设当A方先断开连接时,首先发送FIN = 1,同时消耗一个序列号Seq = u的TCP报文,当B方收到该断开连接的请求时,会发送ACK = 1,ack = u + 1的TCP确认报文,同时消耗一个序列号Seq = v
- 当B方断开连接时,首先也会发送FIN = 1、Seq = w(v不一定等于上面的w,因为B方在A方断开连接时仍然可以发送报文给A方,所以序列号会继续递增,只是A方不能发送报文给B方了),同时ack = u + 1,ACK = 1,最后A方收到该挥手报文后会发送Seq = u + 1,ACK = 1,ack = w + 1的TCP报文
为什么断开连接后需要2MSL的时间才能关闭连接
- 防止4报文挥手的最后一个报文丢失,需要重新发送TCP挥手报文,保证该报文可以到达接收方
- 清除已经失效的连接请求报文段
滑动窗口
滑动机制
-
为什么需要滑动窗口
因为tcp是可靠传输,如果每次只发送一个TCP报文大小的数据,当且仅当收到接收方发来的确认再进行下个TCP报文的发送,效率会非常低,因此引进了滑动窗口机制;
-
滑动窗口使得发送方一次性可以发送多个TCP报文的数据,而且使用滑动窗口的大小(滑动窗口的大小是指无需等待接受方应答的情况下每次能够发送的TCP报文数量)来限制发送方发送的TCP报文数量,当收到接收方的确认报文时才会进行窗口的滑动,从而实现TCP的滑动窗口机制;
-
滑动机制:当发送方将窗口允许的最大TCP报文发送后会进行等待接收方的应答,此时发送方的窗口不会进行移动,只有当收到接收方的报文且该报文的ack对应窗口的第一个序号时才会进行窗口移动
-
举个栗子:如上图所示,滑动窗口大小3个TCP报文的大小,序列号为1和2的TCP报文已经发送并且收到了确认,序列号3、4、5的报文未收到确认,序列号6、7、8的报文未发送,这时如果收到了序列号为3的确认报文则窗口右移一格到序列号4,如果因为网络延迟先收到了确认报文4而未收到确认报文3,那么滑动窗口仍然不会移动,直到收到确认报文
快速重传
滑动窗口内的每个报文在发送后会启动计时器,当计时器超时会重新发送该报文,或者接收方收到了确认报文4、5但是未收到确认报文3,如果启用快速重传机制则接收方在每一次收到报文时都会发送ack = 3的请求报文,请求发送报文序列号为3的TCP报文,当发送方收到3次该TCP请求时会快速将序列号等于3的报文进行发送,无论此时是否超时
流量控制
如果说滑动窗口是在发送方自己控制发送的TCP报文数量,那么流量控制就是发送方根据接收方接受报文的接受能力控制滑动窗口的大小,如果不考虑接受方对TCP报文的接受能力,那么会导致大量TCP超时重发浪费资源
拥塞避免
- 为什么需要拥塞避免:当我们考虑完发送方和接收方对TCP的发送和接受能力后,我们还应该考虑网络负载,即网络对packet的传输能力,试想一下,在考虑了滑动窗口和流量控制后,网络上的每个结点都按此窗口大小发送packet,而此时网络负载无法传输这么多数据,具体表现为堆积在路由器队列中的Packet已满,一些Packet需要被丢弃,这样一来会导致大量Packet被超时重发,然后又被丢弃,如此恶性循环最终整个网络面临崩溃
- 如何判断当前网络出现的阻塞呢?很简单,我们不断地加大窗口,当出现超时重传时则说明超出了当前的网络负载,需要动态调整拥塞窗口
- 调整拥塞窗口过程:cwnd为当前的拥塞窗口大小,ssthresh为提前设定的拥塞窗口阈值
3.1 首先cwnd从1开始递增,以2的N次幂进行递增,当大于等于阈值时会进行拥塞避免,cwnd会以线性增长,ssthread保持不变;
3.2 如果出现3个重复ack会进行快重传,此时cwnd = cwnd / 2,ssthresh = cwnd(不能颠倒2个赋值等式的顺序),接着进行拥塞避免
3.3 如果出现超时重传,此时ssthresh = cwnd / 2,cwnd = 1(不能颠倒2个赋值等式的顺序),然后开始进行慢开始
提高网络利用率
捎带传输
捎带传输是指当A方接受到B方发送的TCP报文时不会立即发送确认报文,而是等到B方要发送TCP报文给A方时才捎带传输ack确认号,捎带传输需要建立在延迟确认应答(即等到要发送报文才发送确认号ack)的基础上
TCP首部
我们简要挑几个重点的描述下即可:
- 数据偏移:当数据部分超过MSS时需要在TCP层(传输层)进行分片,接收方在收到后需要在TCP层进行组装,相同首部的每个TCP报文的数据的数据偏移量进行排序组装
- 控制位有同步标志位SYN、释放连接标志位FIN等
- 窗口大小指接收方允许发送方发送的报文数量
- 校验和指将首部和数据部分放在一起使用二进制反码计算后放入校验和,接收方接收后对首部和数据进行再次计算,最后和二进制反码进行叠加,全为1则正确
TCP的特点总结
- TCP需要在通信之前建立连接、通信完成释放连接,仅仅支持一对一通信,支持全双工通信
- TCP首部开销较大,除了固定的20字节首部之外还有option选项
- TCP具有可靠传输、滑动窗口、流控制、拥塞控制、提高网络利用率等机制确保packet的正确发送以及接收
- TCP面向字节流,即无论应用层交付的报文多长,都会按照Min{MSS(接收方)、MSS(发送方)}决定MSS,将报文按MSS进行分片,确保在网络层不会被进行分片
UCP协议
不可靠的UDP的应用场景
UDP传输协议主要应用在实时的场景,如直播,微信电话等场景,追求的是实时而不是可靠传输,如域名解析的DNS使用的也是UDP协议
UDP首部
UDP首部包括源端口号、目的端口号、(首部+数据)的长度,检验和,UDP会将应用层交付下来的数据原封不动的添加UDP首部后交付给网络层,如果出现长度大于MTU,会在网络层进行分片
WireShark验证UDP首部
- DNS域名解析协议在传输层是使用UDP协议作为数据传输协议;
- 使用wireshark捕获ping www.baidu.com命令百度网站响应的packet时会进行域名解析,解析结果如图3;
- 点开发现DNS确实使用了UDP协议,发现UDP首部依次为Source Port(源端口),Destination(目的端口),Length以及Checksum(检验和)
- Length:UDP首部和数据总和的字节数,上图UDP数据部分为316字节,上面的源、目的端口,长度,检验和各占2个字节,共316 + 2 + 2 + 2 + 2 = 324,刚好是上图UDP包的Length = 324的长度
UDP的特点总结
- DUP协议用于实时的应用场景,不需要提前建立连接,不具有可靠传输的能力,只能尽最大努力交付UDP报文
- UDP协议面向报文段(即不处理应用层交付下来的报文,直接进行对报文添加UDP首部后交付网络层)
- UDP协议支持一对一、一对多、多对多的交互通信
- UDP首部开销较小
通信识别
1.以下通信识别适用于TCP和UDP协议
2. 通信识别是指识别是否是相同发送方、接收方应用层之间的通信(识别端口号之后会交付TCP/UDP的上一层应用层)
3. 识别过程
参考文献:
《计算机网络》
《图解TCP_IP》