五、运输层

五、运输层

5.1TCP

5.1.1TCP和UDP区别?

1) TCP面向连接,UDP无连接;

2) TCP保证数据的可靠传输,数据传送无差错,不丢失,无重复,按序到达;

3) TCP连接点对点单播,UDP 支持单播、多播、广播;

4) UDP 设计简单,实时性好,效率高,适用于很多应用,如:多媒体应用等;

TCP 设计复杂,用于大多数应用,如:万维网、电子邮件、文件传送等。

5) TCP面向数据流, UDP面向数据报。

5.1.2TCP如何实现可靠传输?

TCP 提供了面向字节的差错控制。

TCP 提供了面向字节的流量控制。发送 TCP 要对能接受多少从发送进程传来的字节进行控制;接收 TCP 则要对发送 TCP 能够发送多少字节进行控制。

TCP 提供了拥塞控制。发送方允许发送的数据量不仅要受接收方的控制(流量控制),而且还要由网络的拥塞状况来决定。

5.1.3什么是确认重传机制?

在发送一个数据之后,就开启一个定时器,若是在这个时间内没有收到发送数据的ACK确认报文,则对该报文进行重传,在达到一定次数还没有成功时放弃并发送一个复位信号。

A.累计确认

累计确认就是TCP协议的确认方法,TCP使用可变长度报文段来发送数据,重传时, 报文段数据可能会比原报文段数据包含更多的数据,因此对数据报和报文段无法进行简单的确认。TCP使用流序号对流中的一个位置进行确认,即序号和确认号--对应, 接收方使用序号将报文段重新排序,且以正确接收到的流的最长连续前缀确认。

 

B.超时重传

超时时间计算是开启定时器的设定时间,从而保证网络资源利用率,避免因定时器的时间(RTO)不确定而影响网络传输效率。

C.快速重传

后面拥塞控制章节会讲。

5.1.4为什么要流量控制?

通信双方在数据传输时,发送方的速率与接收方的速率是不一定相等,如果发送方的发送速率太快,会导致接收方处理不过来,这时候接收方只能把处理不过来的数据存在缓存区里(失序的数据包也会被存放在缓存区里)。

如果缓存区满了发送方还在疯狂着发送数据,接收方只能把收到的数据包丢掉,大量的丢包会极大着浪费网络资源,因此,我们需要控制发送方的发送速率,让接收方与发送方处于一种动态平衡才好。

故对发送方发送速率的控制,我们称之为流量控制。

5.1.5什么是滑动窗口协议?

我们在TCP如何实现可靠传输一章中说道TCP实现有序传输采用了确认应答机制,如果通信双发仅接收到一帧,确认一帧,再发送一帧,实现简单的停止等待协议。那么整个网络的吞吐量将会非常的低。

滑动窗口协议用于网络数据传输时的流量控制,以避免拥塞的发生。 该协议允许发送方在停止并等待确认前发送多个数据分组。由于发送方不必每发-个分组就停下来等待确认,因此该协议可以加速数据的传输,提高网络吞吐量。

它本质上是描述接收方数据报缓冲区大小的数据,发送方根据这个数据来计算自己最多能发送多长的数据。这个窗口大小为0时,发送方将停止发送数据。启动定时器,等待这个窗口变成非0。

滑动窗口协议必须保证数据包的按序传输,发送窗口中的序列号代表已发送但尚未收到确认的数据包,发送窗口可持续地维持一系列未经确认的数据包,因为发送方窗口内的数据包可能在传输过程中丢失或损坏,所以发送过程必须把发送窗口中的所有数据包保存起来以备重传。发送窗口一旦达到最大值,发送过程就必须停止接收新的数据包,直到有空闲缓存区。

接收窗口外的数据包都要丢弃,当序列号等于接收窗口下限的数据包到达时,把它提交给应用程序并向发送端发送确认,接收窗口向前移动一位。发送窗口和接收窗口上下限无需相同,大小也无需相同,但接收窗口大小需保持固定,发送窗口大小可随着数据包而改变。如何控制1)接收方ACK报文会携带窗口信息,发送方收到之后,便会调整自己的发送速率,也就是调整自己发送窗口的大小;

2)发送方接收到rwnd==0的报文后停止发送,并启动定时器,每隔- -段时间就发个测试报文去询问接收方接收窗口大小,即等待接收方rwnd>0的报文。

5.1.5.1接收窗口大小是否固定?

TCP是双工的协议,会话双方都可以同时接收、发送数据。TCP会话双方都各自维护一个发送窗口和一个接收窗口,各自的接收窗口大小取决于应用、系统、硬件的限制。当链路变好或者变差,这个窗口会 发生变化。

PS: 在早期的TC协议中,接受接受窗口的大小确实是固定的,不过随着网络的快速发展,固定大小的窗口太不灵活了,成为TCP性能瓶颈之。

5.1.5.2接收窗口越大越好吗?

接受窗口如果太小的话,显然这是不行的,这会严重浪费链路利用率,增加丢包率。那是否越大越好呢?答否,当接收窗口达到某个值的时候,再增大的话也不怎么会减少丢包率的了,而且还会更加消耗内存。所以接收窗口的大小必须根据网络环境以及发送发的的拥塞窗口来动态调整。

5.1.5.3接收双发窗口大小是否相等?

接收方在发送确认报文的时候,会告诉发送发自己的接收窗口大小,而发送方的发送窗口会据此来设置自己的发送窗口,但这并不意味着他们就会相等。首先接收方把确认报文发出去的那一刻,就已经在-边处理堆在自己缓存区的数据了,所以一般情况下接收窗口>=发送窗口。

5.1.6TCP如何进行拥塞控制的?

所谓拥塞控制,就是提高网络利用率,降低丢包率并保证网络资源的对每条数据流的公平性。拥塞控制是一个全局性的过程,涉及到所有的主机、路由器,以及与降低网络传输性能有关的所有因素。路由器的内存是有限的,若同一时间到达某个路由器的数据太多,这个路由器将无法接收所有的数据,只能将一部分丢弃;或者同一台路由器数据太多,后面到达的数据将要等待较长的时间才会被转发。网络中的数据太多,导致某个路由器处理不过来或处理地太慢,这就是网络拥塞。若是对于TCP这种有重传机制的传输协议,当发生数据丢失时,重传数据将延长数据到达的时间;同时,高频率的重传,也将导致网络的拥塞得不到缓解。拥塞控制,就是在网络中发生拥塞时,减少向网络中发送数据的速度,防止造成恶性循环;同时在网络空闲时,提高发送数据的速度,最大限度地利用网络资源。

 

TCP协议自己判断网络的拥塞情况。当TCP检测到网络拥塞,则降低数据的发送速率,否则增加数据的发送速率。

  了解TCP的应该知道,TCP不是发送一个数据段,接收到确认后再发送另一个数据段,它采用的是流水线的方式。TCP的每一个数据段都有一个序号,而TCP维护一个发送窗口来发送是数据,这个窗口就是一个区间。所有序号位于这个窗口内的数据段都会被一次性发送,而不需要等待之前发送的数据段被确认。而每当最早发送出去的数据段被确认,窗口就会向前移动,直到移动到第一个没有被确认的序号,这时候又会有新的数据段序号被包含在窗口中,然后被发送出去。所以限制数据发送速率最好的方式就是限制窗口的大小。在发送方的TCP程序会跟踪和维护一个叫做拥塞窗口的变量,用来进行拥塞控制。拥塞窗口被称为cwnd。在TCP发送端,所有被发送但是还没收到确认的数据段必须落在这个窗口中,所有,当网络拥塞时,TCP程序将减小cwnd,而网络通畅时,增大cwnd,以此来控制数据发送的速率。

 

  接着来回答第二个问题。TCP程序将通过数据发送的一些现象来推测网络是否拥塞,比如:

  • 若发送一条数据段后,成功接收到了接收方的确认报文,则可以认为网络没有拥塞;

  • 若发送出一条数据段后,在规定时间内没有收到确认报文(丢失或时延太大),则可以认为网络出现了拥塞;

  • 若连续收到接收方对同一条报文的三次冗余确认(也就是四次确认),则可以推测那条报文丢失,即发生了拥塞;

 

  上面的第三种情况,与TCP快速重传机制有关。TCP无法保证数据能够按顺序到达接收端,所以,可能出现序号靠后的数据报反倒先到达的情况。而TCP接收方并不是接收到哪一条报文,就向发送方发送哪条报文的确认,它是通过发送当前应该接收到的序号最小的报文进行确认。举个例子:

 

  1. 发送方同时发送了1,2,3,4,5这五个序号的报文,假设接收方接收到序号1的报文,于是将向发送方发送一个确认号为2的确认报文(TCP发送方通过确认号来判断接收方接收到的报文),告诉发送方我已经收到2之前的报文了,下一条报文我想要2
  2. 接收方接收到2号报文后,发送确认号3,告诉发送方我接收到了3之前的所有报文;
  3. 这时候因为网络的不确定性,在3号没有到达前,4号报文先到达了,接收方接收到后,将它放入缓存,并依旧回复确认号3,表示它需要的是3号报文;
  4. 可是,之后到达的却5,于是它将5放入缓存,并依旧回复3;
  5. 直到3迟迟的到来,这时候接收方接收3,同时发现缓存中存在4和5,于是回复发送方确认号6,表示自己已经接收到了6之前的全部报文,下一条需要6

 

  在这里,发送方一共接收到了三条确认号为3的确认报文(确认号为3是对2号报文的确认),第一条正常,后面两条冗余。而所谓的快速重传就是指:若发送方接收到对同一条报文的三次冗余确认(也就是四次确认),就认为这条报文的下一条已经丢失,于是不管计时器是否超时,都直接重传这条报文的下一条。上面的例子中,2号报文被冗余确认了两次,还不构成快速重传的条件。而为什么是三次,其实就是概率和时间长短的折中选择。

 

  下面回到正题,当快速重传的条件发生,发送方将认为出现了拥塞导致丢包。所有归根到底,TCP判断拥塞的方式就是检测有没有丢包。于是我们就可以回答第三个问题了,TCP如何调整发送速率——在没有丢包时慢慢提高拥塞窗口cwnd的大小,当发生丢包事件时,减少cwnd的大小。当然,具体的算法要复杂的多,TCP调整拥塞窗口的主要算法有 慢启动 , 拥塞避免 以及 快速恢复 ,其中前两个是TCP规范要求必须实现的,而第三个则是推荐实现的,TCP根据情况在这三者之间切换。

拥塞控制的几个主要方法包括:慢启动、拥塞避免、快速重传和快速恢复。

慢启动:

 

  • MSS:最大报文段长度,TCP双方发送的报文段中,包含的数据部分的最大字节数;
  • cwnd:拥塞窗口,TCP发送但还没有得到确认的报文的序号都在这个区间;
  • RTT:往返时间,发送方发送一个报文,到接收这个报文的确认报文所经历的时间;
  • ssthresh:慢启动阈值,慢启动阶段,若cwnd的大小达到这个值,将转换到拥塞避免模式;

 

慢开始并非指拥塞窗口(cwnd) 在过程中增长的慢,而是启动时把拥塞窗口cwnd设置为一个最大报文段MSS的数值。而在每收到一个对新的报文段的确认后,把拥塞窗口增加至多一个MSS的数值(即指数增长)。用这样的方法逐步增大发送方的拥塞窗口,可以使分组注入到网络的速率更加合理,尽快找到上限

拥塞避免:

cwnd增长到一个阈值ssthresh时,就开始使用拥塞避免算法,即每经过一个往返时间RTT就把发送方的cwnd加1,进行线性增长。

判断拥塞发生:

以上是发送端在未检测到拥塞时所采用的积极避免拥塞的方法。接下来介绍拥塞发生时(可能发生在慢启动阶段或者拥塞避免阶段)拥塞控制的行为。先来了解一下发送端可以判断拥塞发生的依据:

传输超时(TCP重传定时器溢出)仍然使用慢启动和拥塞避免算法

做法是把ssthresh置为出现拥塞时的拥塞窗口的一半(但不能小于2) ,以及cwnd置为1进行慢开始。目的是迅速减少主机发送到网络中的分组数,使得发生拥塞的路由器有足够时间把队列中积压的分组处理完毕。

●接收到重复的确认报文段使用快速重传和快速恢复发送端如果连续收到3个重复的确认报文端,就认为是拥塞发生了,具体实现步骤:

1)快速重传(Fast retransmit): 要求接收方在收到一个失序的报文段后就立即发出重复确认(为的是使发送方及早知道有报文段没有到达对方),而不要等到自己发送数据时捎带确认;

 

2)快速恢复(Fast retransmit):发送方一旦收到3个重复确认,就知道现在只是丢失了个别的报文段。于是不启动慢开始算法,而执行快恢复算法;

发送方将慢开始门限ssthresh值和拥塞窗口cwnd值调整为当前窗口的一半;开始执行拥塞避免算法。

也有的快恢复实现是把快恢复开始时的拥塞窗口cwnd值再增大一些,即等于新的ssthresh + 3。

 

 

5.1.7tcp报文格式

 

由上图中的TCP报文格式可知,TCP报文首部有20字节的固定首部以及最大长度为40字节的偏移数据构成,即TCP报文头部最大60字节(计算方式后面会讲)。

其中固定首部包括:

端口号:包括源端口号和目的端口号两部分,分别占2字节,用来标识同一台计算机的不同的应用进程。

TCP报头中的源端口号和目的端口号同IP数据报中的源IP与目的IP唯一确定一条TCP连接。

序列号和确认号:序号是本报文段发送的数据组的第一个字节的序号。在TCP传送的流中,每一个字节一个序号。

如一个报文段的序号为300,此报文段数据部分共有100 字节,则下一个报文段的序号为400。所以序号确保了TCP传输的有序性。确认号,指下一个期待收到的字节序号,表明该序号之前的所有数据已经正确无误的收到。确认号只有当ACK标志为1时才有效。比如建立连接时,SYN 报文的ACK标志位为0。

序号和确认号分别占4字节。

数据偏移或首部长度首部长度也叫数据偏移,因为首部可能含有可选项内容,因此TCP报头的长度是不确定的,首部长度实际上指示了数据区在报文段中的起始偏移值。

由于首部长度只占到了4bit大小,所以能表示的最大长度是2^4-1=15, 同时它的单位是4字节,所以首部最大长度是4*15=60 字

保留:6位

控制位: 6位

包括URG、ACK、PSH、RST、SYN 和FIN六个,每一个标志位表示一个控制功能。

1) URG: 紧急指针标志,为1时表示紧急指针有效, 为0则忽略紧急指针。

2) ACK: 确认序号标志,为1时表示确认号有效,为0表示报文中不含确认信息,忽略确认号字段。

3) PSH: push标志,为1表示是带有push标志的数据,指示接收方在接收到该报文段以后,应尽快将这个报文段交给应用程序,而不是在缓冲区排队。

4) RST:重置连接标志,用于重置由于主机崩溃或其他原因而出现错误的连接。或者用于拒绝非法的报文段和拒绝连接请求。

5) SYN:同步序号,用于建立连接过程,在连接请求中,SYN= 1和ACK=0表示该数据段没有使用捎带的确认域,而连接应答捎带一 个确认,即SYN= 1和ACK=1。

6) FIN: 结束标志,用于释放连接,为1时表示反送万匕经没有数据友达S,即天团本万数据流。

窗口(2字节):滑动窗口大小,用来告知发送端接受端的缓存大小,以此控制发送端发送数据的速率,从而达到流量控制。窗口大小是一个1 6bit的字段,因而窗口大小最大为65535。

校验和(2字节):奇偶校验,此校验和是对整个的TCP报文段,包括TCP头部和TCP数据,以16位字进行计算所得。由发送端计算和存储,并由接收端进行验证。

紧急指针(2字节): 只有当URG标志置1时紧急指针才有效。紧急指针是-个正的偏移量,和顺序号字段中的值相加表示紧急数据最后- -个字节的序号。TCP的紧急方式是发送端向另一-端发送紧急数据的一种方式。

选项和填充:最常见的可选字段是最长报文大小,又称为MSS (Maximum Segment Size),每 个连接方通常都在通信的第一个报文段 (为建立连接而设置SYN标志为1的那个段)中指明这个选项,它表示本端所能接受的最大报文段的长度。选项长度不一定是32位的整数倍,所以要加填充位,即在这个字段中加入额外的零,以保证TCP头是32的整数倍。

5.1.8三次握手和四次挥手的过程

三次握手

 

 

 

 

①首先 Client 端发送连接请求报文

②Server 段接受连接后回复 ACK 报文,并为这次连接分配资源。

③Client 端接收到 ACK 报文后也向 Server 段发生 ACK 报文,并分配资源,这样 TCP 连接就建立了。

 

如果只有两次握手 这个时候客户端没有回应,这样会浪费服务端的资源

 

那你是否思考过为什么需要第三次通信 ?

1、在第一次通信过程中,A向B发送信息之后,B收到信息后可以确认自己的收信能力和A的发信能力没有问题。

2、在第二次通信中,B向A发送信息之后,A可以确认自己的发信能力和B的收信能力没有问题,但是B不知道自己的发信能力到底如何,所以就需要第三次通信。

3、在第三次通信中,A向B发送信息之后,B就可以确认自己的发信能力没有问题。

4、 小结:3次握手完成两个重要的功能,既要双方做好发送数据的准备工作(双方都知道彼此已准备好),也要允许双方就初始序列号进行协商,这个序列号在握手过程中被发送和确认。

 

TCP的四次挥手

建立连接非常重要,它是数据正确传输的前提;断开连接同样重要,它让计算机释放不再使用的资源。如果连接不能正常断开,不仅会造成数据传输错误,还会导致套接字不能关闭,持续占用资源,如果并发量高,服务器压力堪忧。

 

 

第一次挥手:Clien发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。

第二次挥手:Server收到FIN后,发送一个ACK给Client,Server进入CLOSE_WAIT状态。

第三次挥手: Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态。

第四次挥手:Client收到FIN后,Client进入TIME_WAIT状态,发送ACK给Server,Server进入CLOSED状态,完成四次握手。

数据传输完毕后,双方都可释放连接。最开始的时候,客户端和服务器都是处于ESTABLISHED状态,然后客户端主动关闭,服务器被动关闭。

 

为什么连接的时候是三次握手,关闭的时候却是四次握手?

 

①因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。

②但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,“你发的FIN报文我收到了”。

③只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。

 

TCP的三次握手一定能保证传输可靠吗?不能

三次握手比两次更可靠,但也不是完全可靠,而追加更多次握手也不能使连接更可靠了。因此选择了三次握手。

世界上不存在完全可靠的通信协议。从通信时间成本空间成本以及可靠度来讲,选择了“三次握手”作为点对点通信的一般规则。

 

为何不能两次握手进行连接?

三次握手完成了两个重要的功能,既要双方做好发送数据的准备工作(双方都知道彼此已准备好),也要允许双方就初始序列号进行协商,这个序列号在握手过程中被发送和确认。如果把三次握手改成仅需要两次握手,可能会造成死锁是。

如计算机S和C之间的通信,假定C给S发送-个连接请求分组,S收到了这个分组,并发送了确认应答分组。按照两次握手的协定,S认为连接已经成功地建立了,可以开始发送数据分组。可是,C在S的应答分组在传输中被丢失的情况下,将不知道S是否已准备好,不知道S建立什么样的序列号,C甚至怀疑S是否收到自己的连接请求分组。在这种情况下,C认为连接还未建立成功,将忽略S发来的任何数据分组,只等待连接确认应答分组。而S在发出的分组超时后,重复发送同样的分组。这样就形成了死锁。

 

 

什么是TCP粘包和拆包?

TCP粘包就是指发送方发送的若干包数据到达接收方时粘成了一包,从接收缓冲区来看,后-包数据的头紧接着前一包数据的尾,出现粘包的原因是多方面的,可能是来自发送方,也可能是来自接收方。

 

为什么会产生这样的现象?

这是由于TCP为提高性能,发送端会将需要发送的数据发送到缓冲区,等待缓冲区满了之后,再将缓冲中的数据发送到接收方。同理,接收方也有缓冲区这样的机制,来接收数据。

而UDP则是面向消息传输的,是有保护消息边界的,接收方-次只接受一条独立的信息,所以不存在粘包问题。

 

如何处理粘包现象?

1)对于发送方造成的粘包问题,可以通过关闭Nagle算法来解决,使用TCP_ NODEL AY选项来关闭算法;

2)接收方没有办法来处理粘包现象,只能将问题交给应用层来处理;

3)应用层的解决办法简单可行,不仅能解决接收方的粘包问题,还可以解决发送方的粘包问题。

 

循环处理,应用程序从接收缓存中读取分组时,读完一条数据,就应该循环读取下一条数据,直到所有数据都被处理完成,但是如何判断每条数据的长度呢?

●格式化数据:每条数据有固定的格式(开始符,结束符),这种方法简单易行,但是选择开始符和结束符时一 定要确保每条数据的内部不包含开始符和结束符。

●发送长度:发送每条数据时,将数据的长度一 并发送,例如规定数据的前4位是数据的长度,应用层在处理时可以根据长度来判断每个分组的开始和结束位置。

5.2 UDP

1、UDP 是无连接的,发送数据之前不需要建立连接,因此减少了开销和发送数据之前的时延。

2、UDP 使用尽最大努力交付,即不保证可靠交付,因此主机不需要维持复杂的连接状态表。

3、UDP 是面向报文的。UDP 对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界。应用层交给 UDP 多长的报文,UDP 就照样发送。

4、UDP 没有拥塞控制,因此网络出现的拥塞不会使源主机的发送速率降低。这对某些实时应用是很重要的。很适合多媒体通信的要求。

5、UDP 支持一对一、一对多、多对一和多对多的交互通信。

6、UDP 的首部开销小,只有 8 个字节,比 TCP 的 20 个字节的首部要短。

 

posted @ 2022-08-15 22:09  石元  阅读(58)  评论(0编辑  收藏  举报