浅谈网络-UDP与TCP

提到UDP和TCP,可能大家并不陌生,多少这两个协议也是混的耳熟,在面试啊什么的场景下提问的话,一般都会问这两者的区别,大部分人都会回答,首先他们是基于传输层的,TCP是面向连接的,是可信的,UDP是面向无连接的,是不可信的。那么什么是面向连接的,什么是面向无连接呢?还有就是为什么他们回可信和不可信呢?如果说三次握手的话,那我UDP也发三个包进行尝试,这样有区别吗?接下来咱们就进行讨论分析下。

一.TCP和UDP的区别

TCP是面向连接的,UDP是面向无连接的。要了解两者的区别,首要需要了解的是什么是面向连接/无连接?所谓的建立连接,是指客户端和无服务为了维护连接,建立的一定的数据结构来维护双方的交互状态,用这两的数据结构来保证所谓的面向连接的特性。

1.TCP提供可靠的数据传输,而UDP可能会丢包,不保证数据包会按顺序到达。
2.TCP是面向字节流的,发送的时候是一个流,无头无尾,而UDP是基于数据报的,一个个的发,一个个的接受。
3.TCP是有拥塞控制的,而UDP没有
4.TCP是一个有状态服务,也就是说可知道哪些发了,都接受了没有,而UDP是无状态服务,发了就发了

基本来了解了这些区别后,咱们来分别去了解下这两个协议各自的特性,然后对比来知道各自的特征。

二.UDP

首先说UDP,UDP的话是继承与IP协议的,所以也就代表着它的特征更加的近似于IP协议,接下来咱们讲一下他的特点,用途等,帮助更容易的了解它。

1.UDP报文

2.UDP的三大特点

UDP协议相对简单,有以下几个特点:

第一,沟通简单,没有大量的数据结构,处理逻辑等。不回去检查网络环境,默认很容易到达的情况,数据包不容易丢失。

第二,不会建立端到端的连接,只要是向坚挺端口发送包,都会被一视同仁的接受,可以接受任何人发来的数据,也可以传给任何人。

第三,没有拥塞控制等,无论当前网络环境是怎样的,当有发包的需求的时候,就会发出,不会根据网络拥塞情况,丢包情况进行自主调节。

3.UDP的三大应用场景

基于UDP以上的几个特点,一般会在如下几个场景下进行使用。

第一,需要资源少,网络情况比较好并且对于丢包不敏感的应用。例如DHCP就是基于UDP进行实现的,一般获取IP地址都是内网请求,网络环境相对较好,并且就算是当时一次两次获取不到IP也没什么关系,过后重新获取即可。

第二,不需要进行一对一建立连接的,可以广播的应用。对于多播这种情景,可能参考“组播”的概念(IP地址中有一个D类地址,就是组播地址,可以讲包组播给一批设备),使用案例的话,我记得有个协议VXLAN,有兴趣的可以去了解下。「一定要注意的是,ARP协议在应用上也是广播,但是是在网络层的协议,UDP是传输层的,ARP不是基于UDP的」

第三,处理速度快,延时低。当前很多应用都是要求低延时的,丢包的话丢就丢了,没必要重新传,网络延迟大的话也要正常发出这样的情况。例如很多即时对战的游戏就使用UDP,像LOL啊啥的,丢就丢了,但是时延是不能容忍的,当然现在的直播啊,物联网呀这些也大都是选择UDP的。

三.TCP

大体了解了UDP后,接下来咱们来谈谈TCP。与UDP不同,TCP默认网络环境是差的,不可信的,所以就会使用一定的算法,来保证传说的可靠性。

1.TCP报文

对比来看UDP的报文样式,可知道TCP的报文中多处了很多东西,例如序号,确认序号,窗口大小等,那这些都是干什么的呢?

包的序号是为了解决乱序的问题。确认哪个应该先来,哪个应该后到。

确认序号是将包发出去后,回包说已经确认到达的数据。确认哪些需要补发。

TCP首部中有6个标志比特,它们中的多个可同时被设置为1,主要是用于操控TCP的状态机的,依次为URG,ACK,PSH,RST,SYN,FIN。时序图的时候需要用到,意义如下:

URG:此标志表示TCP包的紧急指针域(后面马上就要说到)有效,用来保证TCP连接不被中断,并且督促中间层设备要尽快处理这些数据;

ACK:此标志表示应答域有效,就是说前面所说的TCP应答号将会包含在TCP数据包中;有两个取值:0和1,为1的时候表示应答域有效,反之为0;

PSH:这个标志位表示Push操作。所谓Push操作就是指在数据包到达接收端以后,立即传送给应用程序,而不是在缓冲区中排队;

RST:这个标志表示连接复位请求。用来复位那些产生错误的连接,也被用来拒绝错误和非法的数据包;

SYN:表示同步序号,用来建立连接。SYN标志位和ACK标志位搭配使用,当连接请求的时候,SYN=1,ACK=0;连接被响应的时候,SYN=1,ACK=1;这个标志的数据包经常被用来进行端口扫描。扫描者发送一个只有SYN的数据包,如果对方主机响应了一个数据包回来 ,就表明这台主机存在这个端口;但是由于这种扫描方式只是进行TCP三次握手的第一次握手,因此这种扫描的成功表示被扫描的机器不很安全,一台安全的主机将会强制要求一个连接严格的进行TCP的三次握手;

FIN: 表示发送端已经达到数据末尾,也就是说双方的数据传送完成,没有数据可以传送了,发送FIN标志位的TCP数据包后,连接将被断开。这个标志的数据包也经常被用于进行端口扫描。

窗口大小主要作用是来限制传输的速度。不要一次性发送大量数据,处理不过来,也不要太少,不够处理资源浪费。就是之前说的拥塞控制。是根据发包情况来计算得到的。

2.经典的三次握手

不得不说的是,每次说到TCP协议,一定要讲的就是这三次握手,TCP连接的建立,我们称之为三次握手,这是保证TCP协议可靠特性的保障。「要注意的是,三次握手除了双方建立连接外,主要还是为了沟通一件事情,就是TCP 包的序号的问题。」

一开始,客户端和服务端都处于 CLOSED 状态。先是服务端主动监听某个端口,处于 LISTEN 状态。然后客户端主动发起连接 SYN,之后处于 SYN-SENT 状态。服务端收到发起的连接,返回 SYN,并且 ACK 客户端的 SYN,之后处于 SYN-RCVD 状态。客户端收到服务端发送的 SYN 和 ACK 之后,发送 ACK 的 ACK,之后处于 ESTABLISHED 状态,因为它一发一收成功了。服务端收到 ACK 的 ACK 之后,处于 ESTABLISHED 状态,因为它也一发一收了。

3.四次挥手

三次握手是建立可信连接的时候很重要的手段,那么断开连接的时候,为什么也要四次挥手这么复杂的流程?这是因为服务端的LISTEN状态下的SOCKET当收到SYN报文的连接请求后,它可以把ACK和SYN(ACK起应答作用,而SYN起同步作用)放在一个报文里来发送。但关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据都全部发送给对方了,所以你可能未必会马上会关闭SOCKET,也即你可能还需要发送一些数据给对方之后,再发送FIN报文给对方来表示你同意现在可以关闭连接了,所以它这里的ACK报文和FIN报文多数情况下都是分开发送的。

「注意,在四次挥手的时候会设置MSL(报文最大生存时间),超过设置时长后会被丢弃」

4.TCP状态机

里面每个步骤概念可能较为复杂,将连接建立和连接断开的两个时序状态图综合起来,就是这个著名的 TCP 的状态机。学习的时候比较建议将这个状态机和时序状态机对照着看,会事半功倍。

下图中,加黑加粗的部分,是上面说到的主要流程,其中阿拉伯数字的序号,是连接过程中的顺序,而大写中文数字的序号,是连接断开过程中的顺序。加粗的实线是客户端 A 的状态变迁,加粗的虚线是服务端 B 的状态变迁。

5.TCP传输策略

TCP是如何传输的呢?TCP为了保证顺序性会给每个传输包一个编号ID,在建立连接的时候就会商定好,传输是从哪个ID开始,然后按照标号ID一个一个的进行顺序传输。传输完成后会有应答,不过需要注意的是,这里的应答不会是收到了哪个包,而是收到了哪个ID以前的所有包。这种应答被称为累计应答。那么就会引申下来,发送端发送缓存情况和接收端接受情况会在各自存储中分别记录。

发送端的话会被分为4部分:发送了已确认的;发送了待确认的;没有发送的,等待发送的;没有发送的,暂不发送的。如下图示例:


其中LastByteAcked代表第一部分和第二部分分割;LastByteSent代表第二和第三部分分割;AdvertusedWindow是指的窗口大小(报文那里提到的限制传输的速度的那个窗口),在图中是加粗的黑框,黑框的大小来源于接受端处理能力,框内为第三部分,框外为第四部分。

接受端的话会被分为三部分:接受并已确认过的;还没有接受,可处理的;还没有接受,超出处理范围的。如下图所示:


其中LastByteRead代表已经接受了,但是未被应用层读取的;NextByteExpected是第一部分和第二部分分割线;MaxRcvBuffer是最大缓存量;窗口大小基本计算AdvertisedWindow=MaxRcvBuffer-((NextByteExpected-1)-LastByteRead)。「要注意的是,发送端的窗口大小是取决与接受端处理能力,控制这我们的流量大小和拥塞情况,当然后面也有了TCP 拥塞控制的 BBR拥塞算法,都会影响窗口的大小,不仅仅是上面那个公式那么简单」

这两个图中,可以得到的信息是,123 发送并接受成功来;45接受成功的回包没收到,应该是回报在路上或者丢了;6789发送了,先收到了89,67在路上或者丢了,位置给他们预留着。那么怎么判断包是丢了还是在路上呢?这里就用到了超时重发,也就是对每个包都设置一个定时器,超过了这个时间就进行重发。那么这个时间是怎么来的呢?这里用到了自适应重传算法,即是估计往返时间,过程是, TCP 通过采样 RTT 的时间,然后进行加权平均,算出一个值,而且这个值还是要不断变化的,因为网络状况不断的变化。除了采样 RTT,还要采样 RTT 的波动范围,计算出一个估计的超时时间。「需要注意的是:TCP 对于超时重传的包的策略是超时间隔加倍。每当遇到一次超时重传的时候,都会将下一次超时时间间隔设为先前值的两倍。两次超时,就说明网络环境差,不宜频繁反复发送。」,以下是超时冲出按具体过程:

一条 TCP 连接开始,cwnd 设置为一个报文段,一次只能发送一个;当收到这一个确认的时候,cwnd 加一,于是一次能够发送两个;当这两个的确认到来的时候,每个确认 cwnd 加一,两个确认 cwnd 加二,于是一次能够发送四个;当这四个的确认到来的时候,每个确认 cwnd 加一,四个确认 cwnd 加四,于是一次能够发送八个。可以看出这是指数性的增长。

有一个值 ssthresh 为 65535 个字节,当超过这个值的时候,要慢下来。

每收到一个确认后,cwnd 增加 1/cwnd,接着上面的过程来,一次发送八个,当八个确认到来的时候,每个确认增加 1/8,八个确认一共 cwnd 增加 1,于是一次能够发送九个,变成了线性增长。

拥塞的一种表现形式是丢包,需要超时重传,这个时候,将 sshresh 设为 cwnd/2,将 cwnd 设为 1,重新开始慢启动。但是这种方式会造成网络卡顿。

快速重传算法。 当接收端发现丢了一个中间包的时候,发送三次前一个包的 ACK,于是发送端就会快速的重传,不必等待超时再重传。TCP 认为这种情况不严重,因为大部分没丢,只丢了一小部分,cwnd 减半为 cwnd/2,然后 sshthresh = cwnd,当三个包返回的时候,cwnd = sshthresh + 3,是还在比较高的值,呈线性增长。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章