网络原理(三)—— 传输层 之 UDP 和 TCP协议

传输层

在传输层两大关键的协议就是UDP和TCP协议了,除此之外,还有别的传输层协议,本文章将介绍UDP和TCP协议,重点介绍TCP协议。

首先回顾TCP和UDP 的特点:

UDP:不可靠传输,面向数据包,全双工

TCP:可靠传输,面向字节流,全双工

UDP 协议

UDP报文格式:

源端口号和目的端口号耳熟能详了。

UDP长度是指整个UDP数据包的长度(报头 + 载荷),由于是16位的长度,所以整个UDP数据包最大的长度 就是 2^16-1 个字节(单位是字节 )即 64KB

16位UDP校验和是校验UDP数据包有没有出错,这和 https 的校验和不一样,https 是为了防止有人篡改数据,这里的UDP校验和是为了防止出现比特翻转(0->1,1->0),也就是防止原始数据发生比特翻转导致数据错误。

最后就是载荷内容

UDP 数据包的报头固定是64个比特位也就是8个字节。

由于UDP最大长度是68KB,在现在的互联网时代,远远不够用,所以引入了下面的 TCP 协议。

TCP 协议

TCP报文的格式:

32位序号 :该报文的载荷数据的第一个字节的起始编号

32位确认序号:说明该报文的确认报文,确认序号说明自己已经接收到的最后一个数据包的最后一个字节的编号+1,也就是你下一个数据包发送的序号应该凑够这里开始。举个例子:假设一个数据包序号为1000,载荷数据占1000字节,对方正常接收,之后需要返回一个确认报文,该报文的确认序号应该是2001。说明2001前面的全部的数据包已经被接收了。

4位首部长度是指首部最大的长度是多少,单位是(4字节) 。说明TCP报头的最大长度 就是 (2^4 -1)* 4 = 60 字节

确认应答

确认应答是指当一方发送数据到达另一方之后,另一方需要返回一个确认数据包,这就是保证可靠传输的其中一种保证。

在TCP报头中我们发现一个有六个标志位的部分:

当 ack 为 1 的时候,说明这是一个确认应答的数据包。

超时重传

当一方发送完数据包之后,如果迟迟未等到确认应答的话,就会认为改数据包发生了丢包了,因此为了保证可靠传输,我们需要进行重新传输改数据包,这就是超时重传。

保证可靠传输的关键就在于确认应答和超时重传。

连接管理

三次握手

在客户端和服务器建立连接的时候,TCP使用的是三次握手的流程。

首先服务器是被动接收客户端的请求,因此建立连接的发起者一定是客户端,客户端首先发送一个同步报文,然后服务器接收到同步报文之后,就会返回一个确认应答和同步报文,最后客户端返回确认应答数据包。

同步报文的特点是 六个标志位里的 syn 是 1.

为什么是三次握手???

首先TCP是有连接的,具体体现在客户端和服务器分别保存了对端的信息。

连接的建立还需要确保双方的发送能力和接收能力都没问题,能正常进行数据通信。

因此客户端发送syn,如果服务器正常接收,说明客户端的发送能力没有问题,这时候服务器发送syn+ack,此时客户端如果额能正常接收的话,说明客户端知道服务器可以正常接收和发送数据,但是服务器这边不知道客户端是否能正常接收数据,因此客户端需要再次发送一个数据包也就是确认应答数据包ack,服务器接收完毕之后,双方就都确定了对方的接收和发送能力正常,也保存了对端的信息,可以开启会话。
由于我们把 syn 和 ack 合并在一起发送给客户端,所以只需要一次,而不是两次,因此四次握手就没有很大的必要了。两次握手又不足以验证双方各自的发送和接收能力正常
三次握手的作用:

首先初步验证通信链路是否是通畅的

验证双方各自的发送能力和接收能力是否正常(这就是为什么两次握手不行)

协商关键信息(序号是从哪里开始的)

三次握手的状态:

当服务器程序一启动,就会由 CLOSED 状态 切换为 LISTEN 状态。

LISTENED 状态:服务器已经启动,可以随时连接客户端

SYN_SEND 和 SYN_RCVD,分别是 syn 发送和接收状态,一般很难看到,因为TCP连接的建立很快就能发生。

ESTABLISHED:是连接建立完毕的状态,随时可以进行数据通信

四次挥手

首先明确一点就是客户端和服务器都可以主动断开连接。

断开连接一般是四次挥手:

主动申请断开连接的需要先发送一个 FIN 数据包(标识位FIN 为1)

然后接收到 FIN 数据包之后需要返回 ACK

接着发送 FIN

最后 返回ACK

TCP连接就会释放

为什么三次握手第二次的数据包SYN可以和ACK 一起,而四次挥手的中间的 FIN 和 ACK 不能合并呢?
因为三次握手的第二份数据包中SYN和ACK 是由内核决定的,当接收到客户端的SYN 之后,会立即返回syn+ack
然而四次挥手的ack 是由内核决定的,但是 FIN 是由应用程序的代码决定的,当程序执行到 socket.close 之后,才会发送 FIN 数据包

四次挥手的状态:

这里要注意的是:谁先发送 FIN,谁就会进入到 TIME_WAIT 状态

谁后发送FIN ,谁就会进入到 CLOSE_WAIT 状态

异常情况的处理

这里列出四种异常情况。

一、进程崩溃了

进程崩溃和主动退出没有本质区别,虽然进程崩溃了,但是只是应用层不行了,传输层的TCP连接还是存在的,因此这里会发生四次挥手来释放连接

二、主机正常关机了

正常的主机关机流程,关机需要一定的时间,在这段时间中可以进行四次挥手

三、不正常关机

如果是不正常关机,例如台式机断电,那么四次挥手可能就没有挥完。举个例子,如果A关机之前发送了一个FIN,在收到 B 的 FIN 之后,A已经关机了,这就意味着B是永远都收不到 ACK的了,那么由于 B 迟迟没有收到 ACK,那么首先会认为发生了丢包,进行超时重传,当超时重传几次之后还是没有收到ACK,就会认为对端发生了严重的错误,B就会主动放连接。

上面的情况是A发出去 FIN 之后,如果A突然断电,没有发送FIN:

1)接收方突然断电

那么这时候 发送方 发送的业务数据迟迟没有得到确认报文,那么 发送 首先会认为发生丢包开始进行超时重传,等到多次迟迟没有得到回应,这时候就会发触发 "重置TCP连接",发送复位报文(标识位RST为1) ,【复位报文是指重新建立连接,从头来过发送数据】如果没有得到ACK,那么服务器会单方面断开连接。

2)发送方突然断电

这时候客户端不知道是服务器挂了还是服务器只是没有继续发送数据了,那么客户端就会先等着,等待到一定时间之后就会发送一个 "心跳包" ,(心跳包只是为了触发ack,确认一下服务器是否存活,不携带任何业务数据)【这个也叫做保活机制,但是由于TCP发送心跳包的时间过长,一般我们会在应用层重新实现心跳包的逻辑代码】

四、网线断开了

这种情况,站在 A 的视角会认为是第三种情况,A最后会放弃连接

站在B 的视角会认为是第三种情况,B会主动放弃连接。

滑动窗口

由于TCP是可靠传输,那么必定会影响到传输的效率,相比于UDP来说,TCP的传输效率是远远小于UDP的。为了在可靠传输的基础上尽可能提高传输效率,我们使用滑动窗口的概念。

这里的窗口是指接收方的缓冲区的大小,最多可以容纳多少个TCP数据包,当接收方接收完数据后一般会返回ack,其中 ack 里面就会包含接收方剩余窗口容量(对应的就是16位窗口大小),这样发送方就可以根据窗口

大小来进行批量传输数据,就不用一个一个地慢慢传输了。

16 位窗口大小并不是窗口大小的极限值,在TCP报头里还有一个叫做选项的数值,里面有一个数值是窗口扩展因子,假设窗口扩展因子为2,那么窗口大小要左移( << )两位
滑动窗口不能无限大,大了会影响传输效率。

快速重传

由于接收方有窗口(缓冲区),所以如果其中有一个数据包发生了丢包就会触发快速重传那个丢失的数据包,然后继续之前的传输。因为数据包已经在缓冲区排列好了,不需要重新重传已经发送过的数据包

流量控制

流量控制是调整发送方的传输速率,避免接收方不能及时处理数据就导致丢包,那么我们就会引入流量控制。

当接收方处理不过来的时候,发送方会降低发送的速率;当接收方还可以继续处理更多的数据的时候,发送方会提高传输的速率,这就是流量控制。

拥塞控制

由于传输效率还与当前网络的链路有关,如果当前网络占用率高,那么发送方就要降低发送速率,如果当前网络链路占用率低,可以提高发送速率。

慢启动目前已经被弃用,现在使用的是快启动。

首先有一个窗口的阀门值,先发送一个数据包,每轮传输的数据包数量等于前一轮传输的数据包数量 * 2,直到达到窗口的阀门值,之后每轮传输的数据包会 + 1,也就是开始是指数增长的,达到阀门值之后就变成线性增长了。

假设当前窗口大小调整到了24,如上图所示,这时候已经到了网络链路的极限的时候,也就是发生了丢包,发送方收到了连续的 3 个 ack 之后,就会进行快启动,现在窗口阀门值会变成当前窗口的 1/2 也就是 24 / 2 = 12,发送数据量会降到新的阀门值,之后继续进行 + 1 的线性增长

如果是慢启动,新的窗口阀门值还是当前极限窗口的 1/2 也就是12 ,这时候传输的数据包的数量降为1,重新开始 * 2 的指数增长到达阀门值然后进行 + 1 的线性增长

从快启动和慢启动的区别来看,快启动会效率高一些,所以现在我们使用的是快启动。

窗口的实际大小等于 MIN(流量控制的窗口值,拥塞控制的窗口值)

延迟应答

当接收到数据的时候不立即返回 ack,而是等一会再返回 ack,这就是延迟应答

延迟应答可以让接收方有一些时间先处理一下缓冲区(窗口)的数据,这样等一会,窗口就会变得大一些,那么 ack 返回的窗口的大小就可以大一些,那么发送方就可以批量传输更多的数据了,再一定程度上提高了传输效率。

捎带应答

就是在返回 ack 的时候顺便把业务数据也一起带上,捎带应答是配合延迟应答使用的,延迟应答一般是等到接收方需要发送业务数据的时候把 ack 一起带上,这样可以减少网络开销,在一定程度上提高了传输效率。

面向字节流 ------ 粘包问题

由于TCP是面向字节流的,所以在拆包之后,数据可能发生粘包问题,就是拆完包之后分不出哪些数据是一组,哪些数据是另一组。

举个例子,发送方发送 aaa, bbb, ccc 这三个数据包,在接收方的传输层里进行拆包然后数据就可能变成这样 aaabbbccc,交给应用层的时候就无法区分了,这就是粘包问题。

要解决粘包问题需要在应用层处理,在传输层是无解的,在设计应用层协议的时候,我们需要定义好如何区分这些数据,可以像之前我们写TCP回显服务器和客户端一样,使用 \n 这个换行符来进行数据的分割,或者其他的分割方法。

相关推荐
治金的blog3 小时前
Http 响应状态码 前后端联调
网络·网络协议·http
Tic..4 小时前
网络学习记录2
网络
_不会dp不改名_4 小时前
HCIP笔记1--IP路由基础回顾、BFD单臂回声、OSPF基础
网络·笔记·hcip
Parrot 安全小子4 小时前
Wireshark 使用教程:网络分析从入门到精通
网络·测试工具·wireshark
深圳启明云端科技5 小时前
ESP32-C3物联网芯片方案,设备智能化交互联动,无线通信控制技术
网络·物联网·乐鑫·esp32-c3·芯片模组
Tic..6 小时前
网络学习记录6
网络·学习
南桥几晴秋6 小时前
【Linux网络编程】数据链路层 | MAC帧 | ARP协议
网络·mac·数据链路层·arp协议
fox08156 小时前
wsl2上mysql出现ip端口冲突问题
网络·数据库·tcp/ip·mysql·wsl
earthzhang20216 小时前
《深入浅出HTTPS》读书笔记(28):DSA数字签名
开发语言·网络协议·算法·https·1024程序员节
baowxz6 小时前
lwip单网卡多ip的实现
网络·lwip多ip·ping超时延迟大·multiple ip