TCP和UDP

133 阅读10分钟

本文用于个人面试,摘抄自:TCP和UDP详解(非常详细)_tcp udp_Hansionz的博客-CSDN博客

作者: Hansionz

UDP

UDP协议报文格式:

图像2023-6-6 21.01.jpeg

16位UDP长度表示整个数据包(UDP首部+UDP数据)的长度 如果校验和出错,就会直接丢弃UDP校验首部和数据部分。

UDP的特点

1.无连接:只知道对端的IP和端口号就可以发送,不需要建立连接

2.不可靠: 没有确认机制,没有重传机制。如果因为网络故障该段无法发到对方,UDP也不会给应用层返回任何错误信息

3.面相数据报: 应用层交给UDP多长的报文,UDP会原样发送,既不会拆分也不会合并。如果发送100字节,那么接收也必须接受100字节,而不能循环调用10次,每次接收10字节。

4.缓冲区: UDP存在接收缓冲区,但不存在发送缓冲区。因为UDP不保证可靠性,他没有重传机制,当报文丢失时,UDP不需要重新发送,而TCP不同,它必须具备发送缓冲区,当报文丢失时,TCP必须保证重新发送,用户不会管,所以必须要具备发送缓冲区。而UDP的接收缓冲区不能保证收到的UDP报文的顺序和发送UDP报的顺序一致,如果缓冲区满了,再到达的UDP数据报就会被丢弃。

  1. UDP是一种全双工通信协议,UDP协议首部中有一个16位的大长度,也就是说一个UDP能传输的报文长度是64k(包含UDP首部)。如果我们需要传输的数据大于64k,就需要在应用层手动的分包,多次发送,并在接收端手动拼接。基于UDP的应用层协议有,NFS网络文件系统,DNS域名解析协议。

TCP

TCP协议,又称传输控制协议,必须对数据的传输进行控制。

TCP协议报文格式:

图像2023-6-6 21.13.jpeg

端口号、目的端口号:表示数据从哪个进程来,要到哪个进程去。

32位序号:序号是可靠传输的关键因素,TCP要对每个字节都进行编号,比如一个报文段的序号为300,此报文段数据部分共有100个字节,那么下一个报文段的序号为401.

32位确认序号: 每一个ack对应一个确认号,它指明下一个期待收到的字节序号,表名该序号之前的所有数据已经确认无误的收到,确认号只有为1时才有效

4位首部长度,也就是数据偏移:表示该TCP头部有多少个32bit位,所以TCP头部的长度是15*4=60.

6位标志位: URG为了标志紧急指针是否有效

ACK标识确认号是否有效

PSH提示接收端应用程序立即将接收缓冲区的数据拿走

RST为了处理异常连接,告诉连接不一致的以防,我们的链接还没有建立好,要求对方重新建立链接。

SYN请求建立连接,我们把携带SYN标识的称为同步报文段

FIN通知对方,本端要关闭连接了,我们称携带FIN标识的为结束报文段。

16位紧急指针,按序到达是TCP协议保证可靠性的一种机制,但是也存在一些报文项优先被处理的情况,这时就可以设置紧急指针,指向该报文即可,同时将紧急指针有效位置置于1.

16位窗口大小: 如果发送方发送大量数据,接收方接受不过来,会导致大量数据丢失。然后接收方可以发送给发送消息的一方发送的慢一点,这是流量控制。接收方将自己接收缓冲器剩余空间大小告诉发送方,叫做16位窗口大小,发送方可以根据窗口大小来适配发送的速度和大小,窗口大小最大是2的16次方,即64kb。

16位校验和:发送端填充,CRC校验,如果接收端校验不通过,则认为数据有问题。

确认应答机制:

图像2023-6-6 21.29.jpeg

超时重传机制

图像2023-6-6 21.30.jpeg

TCP为了保证性能会动态计算这个超时重传时间。

滑动窗口

图像2023-6-7 09.04.jpeg 确认应答策略对每一个发送的数据段都要给一个ACK确认应答,接收方收到ACK后再发送下一个数据段,但是这样做有一个比较大的缺点,就是性能差,尤其是数据往返的时间较长。

既然一发一收的方式性能较低,那么我们考虑一次发送多条数据,就可以大大的提高性能,它是讲多个段的等待时间重叠在一起。

窗口大小指的是无需等待确认应答而可以急速发送数据的最大值。上图的窗口大小就是4000字节。发送前四个段的时候,不需要等待任何ACK直接发送即可。当收到第一个ACK后滑动窗口就向后移动,继续发送第五个段的数据,然后一次类推。操作系统内核为了维护这个滑动窗口,需要开辟发送缓冲区来记录当前还有哪些数据没有应答。只有确认应答过的数据,才能从缓冲区删掉,窗口越大,则网络的吞吐率就越高。滑动窗口左边代表已经发送过并且确认,可以从发送缓冲区删除了,滑动窗口里面表示的是发送出去但是没有确认,滑动窗口右边代表还没有发送的数据。

图像2023-6-7 09.10.jpeg

如果在这种情况中发生了丢包:

图像2023-6-7 09.19.jpeg

1.数据到达接收方,但是应答报文丢失,可以根据后边的ACK确认。假设发送方发送1-1000的数据,接收方收到返回确认ACK,但是返回的ACK丢失了,另一边发送1001-2000收到的确认ACK2001,就可以认为1-1000数据接收成功。

2.数据包之间丢失:当某一段报文段丢失之后,发送端会一直收到1001这样的ACK,就像提醒发送端我想要的是1001一样,如果发送端主机连续三次收到了同样一个1001这样的应答,就会将对应的数据1001-2000重新发送,这个时候接收端收到了1001之后,再次返回的ACK就是7001了。因为2001-7000接收端之前就已经收到了,被放到了接收端操作系统内核的接收缓冲区中,这种机制被称为高速重发机制,也叫快重传。

快重传要求接收方在收到一个失序的报文段后就立即发出重复确认,而不要等到自己发送数据时捎带确认。快重传规定,发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段,能提高整个网络的吞吐量。

流量控制

接收端处理数据的速度是有限的,如果发送端发的太快,导致接收端的缓冲区被装满,这个时候如果发送端继续发送,就会造成丢包,然后引起丢包重传等等一系列连锁反应。因此TCP支持根据接收端的处理能力,来决定发送端的发送速度,这种机制叫做流量控制。

接收端将自己可以接受的缓冲区大小放入TCP首部中的”窗口大小“字段中,通过ACK确认报文通知发送端。
窗口大小字段越大,说明网络的吞吐量越高,接收端一旦发现自己的缓冲区快满了,就会将窗口大小设置成一个更小的值通知给发送端。
发送端接收到这个窗口之后,就会减慢自己的发送速度,如果接收端缓冲区满了,就会把窗口设置成0,这时发送方不再发送数据,但是需要定期发送一个窗口探测数据段,使接收端把窗口大小告诉发送端。
接收端如何把窗口大小告诉发送端呢,在TCP首部中,有一个16位窗口字段,就是存放了窗口大小的信息,16位数字表示65535,那么TCP窗口大小就是这么大吗?实际上TCP首部40字节选项中还包含了一个窗口扩大因子M,实际窗口大小是窗口字段的值左移M位。接收端窗口如果更新,会向发送端发送一个更新通知,如果这个更新在通知途中丢失了,会导致无法继续通信,所以发送端要定时发送窗口探测包。

拥塞控制

虽然TCP有了滑动窗口这个大杀器能够高效可靠的发送大量的数据,但是如果在刚开始阶段就发送大量的数据,仍然可能引发问题,因为网络上有很多的计算机,可能当前的网络状态就已经比较拥堵,在不清楚当前网络状态下,贸然发送大量饿的数据是很有可能引起雪上加霜的,造成网络更加拥堵。
TCP虽然有了慢启动机制,先法少量的数据探探路,摸清当前的网络拥堵状态,再决定按照多大的速度传输数据。

图像2023-6-7 09.54.jpeg

上面cwnd为拥塞窗口,在发送开始的时候定义拥塞窗口大小为1,每次收到一个ACK应答拥塞窗口加1.每次发送数据包的时候,将拥塞窗口和接收端主机反馈的窗口大小做比较,取较小的值作为实际发送的窗口。

像上面这样的拥塞窗口增长速度,是指数级别的。慢启动只是指初始慢,但增长速度非常快。为了不增长的那么快,因此不能使拥塞窗口单纯的加倍,此处引入一个叫做慢启动的阈值当做拥塞窗口超过这个阈值的时候,不再按照指数方式增长,而是按照线性方式增长。

图像2023-6-7 10.14.jpeg

当TCP开始启动的时候,慢启动的阈值等于窗口最大值
在每次超时重发的时候,慢启动阈值会变成原来的一半同时拥塞窗口置回1

少量的丢包,我们仅仅是触发超时重传,大量的丢包,我们就认为网络拥堵,当TCP通信开始后,网络吞吐量会逐渐上升,随着网络发生拥堵,吞吐量会立刻下降,拥塞控制归根结底是TCP想能尽快地把数据传输给对方,但是又要避免给网络造成太大压力的这种方案。