计算机网络总结系列之【TCP/UDP协议】

目录

简介

UDP——用户数据报协议(User Datagram Protocol)

特点

面向无连接

不可靠性

面向报文段

单播,多播,广播

头部开销小

UDP首部格式

TCP传输控制协议 TCP(Transmission Control Protocol)

特点

面向连接

可靠传输

面向字节流

点对点通信

全双工通信

TCP首部格式

端口号

序号

确认号

头部长度

保留位

标志位

窗口大小

校验和

紧急指针

选项(最多40字节)

连接过程(三次握手)

发生条件

握手过程

常见问题

功能总结

释放过程(四次挥手)

挥手过程

常见问题

功能总结

超时重传

什么是超时重传?

流量控制

什么是流量控制?

控制手段——滑动窗口

功能

拥塞控制

什么是网络拥塞?

拥塞控制算法——慢启动、拥塞避免、快重传和快恢复

功能

总结

UDP和TCP的对比

UDP数据包与TCP字节流的区别


 

简介

在计算机网络中,网络层把分组发送到目的主机,但真正通信的并不是主机,而是主机中的进程。

传输层提供了进程间的逻辑通信,向高层用户屏蔽了下面网络层的细节,使得应用程序看起来像是有一条端到端的逻辑通信信道。

而TCP/UDP协议是传输层最重要的两种协议,提供了应用程序间的通信,它负责数据从发送端到接收端的信息流格式化和保证可靠传输。


UDP——用户数据报协议(User Datagram Protocol)

特点

  • 面向无连接

不需要和 TCP一样在发送数据前进行三次握手建立连接的,想发数据直接可以开始发送

  • 不可靠性

体现在面向无连接的特性上,通信不需要建立连接,想发就发,尽最大可能交付

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

  • 面向报文段

不会对数据报文进行任何拆分和拼接操作,保留报文的边界,只是添加UDP首部,具体来说

在接收端,网络层将数据传递给传输层,UDP 只去除 IP 报文头就传递给应用层,没有拼接操作

在发送端,应用层将数据传递给传输层,UDP 只会给数据增加一个 UDP 首部,然后传递给网络层

如果发送端调用一次sendto,发送100个字节,那么接收端也必须调用对应的一次recvfrom,接收100个字节,而不能循环调用10次recvfrom,每次接收10个字节

所以UDP不能够灵活的控制读写数据的次数和数量

  • 单播,多播,广播

UDP 支持一对一、一对多、多对多、多对一的方式

  • 头部开销小

UDP头部大小8字节,TCP头部大小最小为20字节,最大为60字节,因此UDP传输开销比TCP小,传输数据报文时高效


UDP首部格式

UDP首部只有8个字节,包括源端口、目的端口、报文长度、校验和,12字节的伪首部用于计算检验(只检验,不恢复)时临时添加


TCP传输控制协议 TCP(Transmission Control Protocol)

特点

  • 面向连接

通过三次握手与四次挥手实现连接的建立与释放一对一连接

  • 可靠传输

采取以上多种方式来保证TCP的可靠性传输

  • 面向字节流

TCP不像UDP一样那样一个个报文独立地传输,而是在不保留报文边界的情况下以字节流方式进行传输

  • 点对点通信

每条TCP连接只能是一对一通信

  • 全双工通信

通信双方都有发送缓存和接收缓存,应用进程在任意时刻都可以收发数据


TCP首部格式

端口号

一个TCP连接由四个要素唯一确定:(源IP,源端口号)+ (目地IP,目的端口号)

其中IP地址由上一层IP协议负责传递,源端口号和目地端口各占16位=2字节,也就是端口的范围是2^16=65535

从1024-65535是用户使用的端口范围,另外1024由系统保留

序号

TCP通信过程中某一个传输方向上的字节流的每个字节的序号,通过seq来确认发送的数据有序。如:现在序列号为1000,发送了1000字节,下一个序列号就是2000

确认号

用来响应TCP报文段,对上一次seq序号做出确认,给收到的TCP报文段的序号seq+1

头部长度

标识TCP首部有多少个4字节,4位1111最大表示15,则TCP首部最长为60字节,最短只有前20字节,不带选项

保留位

6位保留供以后使用

标志位

ACK 标识确认号是否有效(确认报文段)

RST 标识要求对方重新建立连接(复位报文段)

SYN 标识请求建立一个连接(同步报文段)

FIN 标识通知对方本端连接即将关闭(结束报文段)

URG 标识紧急指针是否有效

PSH 提示接收端应用程序应该立即从TCP接收缓冲区读取数据,为接收后续数据腾出空间

窗口大小

流量控制的手段,告诉对方本端TCP接收缓冲区还能容纳多少数据,控制对方发送数据的速度

校验和

由发送端填充,接收端对TCP报文段执行CRC校验检验报文是否损坏(包括首部与数据)

紧急指针

在URG=1时才有意义,它和序号字段的值相加,表示最后一个紧急数据的下一字节的序号,用于发送端向接收端发送紧急数据

选项(最多40字节)


连接过程(三次握手)

  • 发生条件

socket编程中,客户端connect时触发三次握手

  • 握手过程

1.第一次握手,客户端主动向服务器发送连接请求

客户端随机生成一个起始序列号ISN(比如是100),并将SYN标志位置1,指明客户端打算连接的服务器的端口,并将该数据包发送给服务器端

2.第二次握手,服务端向客户端发送确认连接请求报文

服务端收到客户端发过来的报文后,发现SYN=1,知道这是一个连接请求,将客户端的起始序列号100保存,并且随机生成一个服务端的起始序列号(比如是300)

然后给客户端回复一段报文,回复报文包含SYN和ACK标志(也就是SYN=1,ACK=1)、序列号seq=300、确认号ack=101(客户端发过来的序列号+1)

3.第三次握手,客户端再次向服务端发送连接确认

客户端收到服务端的回复后发现ACK=1并且ack=101,于是知道服务端收到了序列号为100的那段报文,同时发现SYN=1,知道了服务端同意了这次连接,于是就将服务端的序列号300保存

客户端再回复一段报文给服务端,报文包含ACK标志位(ACK=1)、ack=301(服务端序列号+1)、seq=101(第一次握手时发送报文是占据一个序列号的,所以这次seq就从101开始

需要注意的是不携带数据的ACK报文是不占据序列号的,所以后面第一次正式发送数据时seq还是101

当服务端收到报文后发现ACK=1并且ack=301,就知道客户端收到序列号为300的报文了,就这样客户端和服务端通过TCP建立了连接,可以调用accept函数获取此连接

  • 常见问题

1.为什么要三次握手?可以是两次吗?

答:为了防止客户端已失效的连接请求到达服务器,让服务器错误地打开连接。

解释:客户端发送的连接请求如果在网络中滞留,就会隔很长一段时间才能收到服务器端发送回的连接确认,客户端等待一个超时重传时间后,会请求重新连接。但是这个滞留的连接请求最后还是会到达服务器,如果不进行三次握手,那么服务器就会打开两个连接。如果有三次握手,客户端会忽略之前发送的对滞留连接请求的连接确认,不进行第三次握手,因此就不会打开连接

2.什么是半连接队列和全连接队列?

半连接队列:服务器第一次接到客户端的SYN请求后,将双方未完全建立连接的请求放在半连接队列中

全连接队列:已经完成三次握手,建立起的连接会放在全连接队列中,队列已满则会产生丢包现象

3.第一次、第二次握手可以携带数据吗?为什么?

答:RFC标准规定,SYN位为1的报文段不允许携带数据

解释:前两次握手时,连接并没有真正建立,假如可以携带数据,如果有人恶意攻击服务器,在SYN报文中放入大量数据,服务器会消耗大量资源去处理

4.第三次握手可以携带数据吗?为什么?

答:RFC标准有说明允许第三次握手携带数据

解释:第三次握手时,客户端和服务器已经建立连接,具备正常的收发能力

5.SYN攻击是什么?如何解决?

答:客户端通过配合伪IP向服务器发送大量的半连接请求,当服务器未收到客户端的第三次握手确认时,重发确认请求包,一直超时

由于源地址本身不存在,服务器需要不断重发到超时,伪造的请求SYN包将长时间占用半连接队列,占用服务器资源,导致正常SYN请求因为队列满而被丢弃,引起网络拥塞甚至瘫痪

解决:缩短超时重传时间,增加最大半连接数、过滤网关防护、SYN cookies技术

6.序列号有什么作用?为什么要随机初始化序列号?

答:用来跟踪该端发送的数据量,比如初始序列号是100,发送200字节数据后,下一个数据号变为300,也能用于对重复发送的数据包进行区分

解释:https://blog.csdn.net/wangquan1992/article/details/97900840

  • 功能总结

确认双方收发能力是否正常,指定各自的初始序列号,并同步双方的序列号和确认号,交换TCP窗口大小信息,为后面建立TCP连接,进行可靠传输准备


释放过程(四次挥手)

  • 挥手过程

情景

客户端初始化的序列号ISN=100,服务端初始化的序列号ISN=300。TCP连接成功后客户端总共发送了1000个字节的数据,服务端在客户端发FIN报文前总共回复了2000个字节的数据

1.第一次挥手,客户端要向服务端发送连接释放报文

无论数据传输是否完成,都可以发送释放连接报文并停止发送数据

释放连接报文包含FIN标志位(FIN=1)、序列号seq=1101(100+1+1000,其中的1是建立连接时占的一个序列号)

此时客户端处于FIN-WAIT-1状态

需要注意的是客户端发出FIN报文段后只是不能发数据了,但是还可以正常收数据;另外FIN报文段即使不携带数据也要占据一个序列号

2.第二次挥手,服务端向客户端发送回复确认报文

服务端收到客户端发的FIN报文后给客户端回复确认报文

确认报文包含ACK标志位(ACK=1)、确认号ack=1102(客户端FIN报文序列号seq=1101+1)、序列号seq=2300(300+2000)

此时服务器处于CLOSE-WAIT状态,客户端处于FIN-WAIT-2状态

服务器不是立马给客户端发FIN报文,这个状态还要持续一段时间,因为服务端可能还有数据没发完

3.第三次挥手,服务端向客户端发送连接释放报文

服务端将最后数据(比如50个字节)发送完毕后就向客户端发出连接释放报文

报文包含FIN和ACK标志位(FIN=1,ACK=1)、确认号和第二次挥手一样ack=1102、序列号seq=2350(2300+50)

此时服务器处于LAST-ACK状态

4.第四次挥手,客户端向服务端发送回复确认报文

客户端收到服务端发的FIN报文后,向服务端发出确认报文

确认报文包含ACK标志位(ACK=1)、确认号ack=2351、序列号seq=1102

此时客户端处于TIME-WAIT状态

注意客户端发出确认报文后不是立马释放TCP连接,而是要经过2MSL(Maximum Segment Life最长报文段寿命的2倍时长)后才释放TCP连接。

而服务端一旦收到客户端发出的确认报文就会立马释放TCP连接,变为CLOSED状态,所以服务端结束TCP连接的时间要比客户端早一些

  • 常见问题

1.为什么TCP连接的是时候是3次,关闭时却是4次?

答:因为TCP连接是全双工通信,即客户端、服务器都可以收发数据,则在断开连接时,需要服务器和客户端都确定对方不再发送数据

解释:

第一次挥手,客户端向服务器发送,服务器得知客户端将不再发送数据

第二次挥手,服务器向客户端发送,客户端得知服务器已经知道客户端不再发送数据

第三次挥手,服务器向客户端发送,客户端得知服务器将不再发送数据

第四次挥手,客户端向服务器发送,服务器得知客户端已经知道服务器不再发送数据

第一、二次挥手时,服务器可能还在向客户端发送数据,所以第二次挥手和第三次挥手不能合并

2.什么是2MSL?为什么客户端发出第四次挥手的确认报文后,客户端要等2MSL时间才能释放TCP连接?

答:2MSL是报文段最长寿命时长的2倍,即报文段在TCP连接中可以存活的最长时间

一个确认报文(第四次挥手)+一个请求报文(第三次挥手)

解释:

客户端发送出ACK=1报文后,开始维护2MSL计时器,假设客户端最后发送ACK=1确认收到服务器关闭连接的报文,在网络中滞留没有到达服务器,服务器在一段时间没有收到客户端的ACK=1回复,会重发第三次挥手的连接释放报文。客户端接到此报文,重置2MSL计时器,再次向服务器发送ACK=1报文,如果直到2MSL计时器到时间都没有收到服务器重发的连接释放报文,则客户端释放TCP连接

如果此时客户端已经释放了TCP连接,没有等待2MSL的时间,则不能接到服务器重发的连接释放报文,重发的报文找不到对应的连接,如果再向服务器发送TCP连接请求,此时无法保证两次连接的端口号不同,则可能出现这样的问题:前一次的连接某些数据滞留在网络中,这些延迟数据在建立新连接后到达客户t端,由于新老连接的端口号和IP都一样,TCP协议就认为延迟数据是属于新连接的,新连接就会接收到脏数据,这样就会导致数据包混乱

3.如果已经建立连接,但客户端出现故障了怎么办?

答:采用心跳机制保活

解释:服务器维护一个计时器,每次服务器接到客户端的请求,都会重新复位计时器,如果超过一定时间没有接收到客户端的数据,服务器会向客户端发送一个探测报文,每隔一定时间发送一次,若连续发送一定数量的探测报文没有回应的话,服务器就认为客户端出了故障,关闭连接

  • 功能总结

确保数据传输完成


超时重传

  • 什么是超时重传?

主机A发送数据给B之后,可能因为网络拥堵等原因,数据无法到达主机B

如果主机A在一个特定时间间隔内没有收到B发来的确认应答, 就会进行重发

等待一段时间仍未收到B的确认包,进行第二次重传(每次等待的时间一般是指数增长,列如间隔时间为1s,2s,4s,8s…)

如果这个过程发生在建立三次握手连接时,重传的次数超过系统规定的最大重传次数,系统将该连接信息从半连接队列中删除


流量控制

  • 什么是流量控制?

所谓流量控制,就是如果接收端和发送端对数据包的处理速度不同,如何让双方达成一致,让发送方的发送速率不要太快,让接收方来得及接收

  • 控制手段——滑动窗口

TCP会话的双方都各自维护一个发送窗口和一个接收窗口,它是缓存的一部分,用来暂时存放字节流,发送窗口内的字节都允许被发送,接收窗口内的字节都允许被接收

要弄清什么是滑动窗口,首先要理解TCP缓存中的数据分类

发送方的发送缓存数据分为4类:

1. 已发送,已收到ACK
2. 已发送,未收到ACK
3. 未发送,但允许发送
4. 未发送,但不允许发送

其中类型2、3属于发送窗口

接收方的接收缓存数据分为3类:
1. 已接收
2. 未接收但准备接收
3. 未接收而且不准备接收

其中类型2属于接收窗口

接收窗口大小代表了设备一次能处理多少数据,之后再传给应用层

接收方通过 TCP 报文段中的窗口大小字段,告诉发送方自己的接收窗口大小,发送方根据这个值和其它信息设置自己的发送窗口大小

滑动机制

1.发送窗口只有收到发送窗口内字节的ACK确认,才会移动发送窗口的左边界

2.接收窗口只会对窗口内最后一个按序到达的字节进行确认,当在前面还有字节未接收但收到后面字节的情况下,窗口不会移动,并不对后续字节确认,以此确保对端会对这些数据重传

如下图:接收窗口例如接收窗口已经收到的字节为 {31, 34, 35},其中 {31} 按序到达,而 {32,33} 没有按序收到,因此只对字节 31 进行确认

发送方得到一个字节的确认之后,就知道这个字节之前的所有字节都已经被接收

详见:https://blog.csdn.net/yao5hed/article/details/81046945

  • 功能

流量控制解决了两台主机之间因传送速率而可能引起的丢包问题,在一方面保证了TCP数据传送的可靠性

然而如果网络非常拥堵,此时再发送数据就会加重网络负担,那么发送的数据段很可能超过了最大生存时间也没有到达接收方,就会产生丢包问题


拥塞控制

  • 什么是网络拥塞?

网络拥塞(network congestion)是指在分组交换网络中传送分组的数目太多时,由于存储转发节点的资源有限而造成网络传输性能下降的情况

  • 拥塞控制算法——慢启动、拥塞避免、快重传和快恢复

假设网络中有两台主机A、B已建立TCP连接,A向B发送数据,通过拥塞窗口cwnd来控制每次发送数据包的个数

慢启动

A开始时不会发送大量的数据,而是先探测一下网络的拥塞程度

由小到大逐渐增加拥塞窗口的大小,在没有出现丢包时每收到一个ACK就将拥塞窗口大小+1

向B发送的数据包个数为cwnd = 1,2,4,8,16……即每轮次发送窗口增加一倍,呈指数增长

当达到慢启动阈值ssthresh (假设为16)时,A转而使用拥塞避免算法

拥塞避免

在拥塞避免阶段,每轮次发送窗口加一,呈线性增长

发送数据包个数为cwnd = 16,17,18……24

拥塞窗口肯定不会无限增长,网络传输中必然出现超时事件

假设拥塞窗口大小达到cwnd = 24时,24个报文段在传输过程中丢失4个,B只收到20个报文段,给A依次回复20个确认报文段

一段时间后,丢失的4个报文段的重传计时器超时了,A判断可能出现拥塞

A将慢启动阈值ssthresh设为24/2 = 12,并重新启动慢开始算法,cwnd从1开始指数增长

快重传

假设在传输过程中,A给B发送1,2,3,4,5……N个数据包,如果B收到了1,2,4……却始终没有收到3

这个时候就会重复确认2,意在告诉A,3还没收到,可能已经在网络中丢失

当A连续收到了三个确认2的ACK,且3的超时事件还没发生。A就知道3可能丢失了,这个时候A就不必等待3设置的计时器到期了,而是快速重传3

快恢复

快恢复配合快重传使用,把阈值ssthresh设置为N的一半,即ssthresh = N/2

但是此时并非把拥塞窗口cwnd重新设置为1,而是让cwnd = ssthresh,重新开始拥塞避免算法的线性增长

详见:

https://zhuanlan.zhihu.com/p/97709686

https://blog.csdn.net/m0_37962600/article/details/79993310

  • 功能

防止过多的数据注入到网络当中,这样可以使网络中的路由器或链路不致过载


总结

UDP和TCP的对比

UDP数据包与TCP字节流的区别


发送端每执行一次sendto(),UDP就将其封装成数据报发送,接收端必须及时针对每一个UDP数据报执行recvfrom(),否则将会丢包

发送端执行send时,TCP先将数据放入TCP发送缓冲区中,当TCP真正开始发送数据后,将数据封装成一个或多个TCP报文段发出,接收端接到一个或多个报文段后,TCP模块将数据按TCP报文段的序号依次放入TCP接收缓冲区,通知接收端recv()读取数据,接收端可以一次性读,也可以分次读,取决于读缓冲区大小

猜你喜欢

转载自blog.csdn.net/qq_37348221/article/details/114572978
今日推荐