计算机网络学习之运输层

瘦欲@ 提交于 2019-11-26 17:08:29


谢希仁老师的计算机网络学习(第六版),主要是记录下TCP/UDP。
首先记录一些需要复习的概念:

(1)运输层是应用层下面的一个层,它提供的是应用进程之间的逻辑通信,和下面几个层是主机间逻辑通信不同,同理,运输层也并不是在两个运输层之间直接传送数据。运输层也是对应用层屏蔽了下面的网络细节的,使得应用进程看见的就是好像在两个运输层实体之间有一条端到端的逻辑通信信道。

(2)运输层有两个主要的协议:TCP/UDP(传输控制协议/用户数据报协议)。它们都具有复用和分用,以及检错的功能,运输层采用面向连接的TCP协议时,尽管下面的网络是不可靠的,只提供最大努力服务,但是这种逻辑通信信道就相当于一条全双工通信的可靠信道,但是采用面向报文的无连接的UDP协议时,这种逻辑通信信道依然是不可靠的信道。

(3)运输层用一个16位的端口号来标志一个端口。端口号只是具有本地意义,它只是为了标志本计算机应用层中的各个进程和运输层进行交互时的层间接口,在不同的计算机中,相同的端口号无关联。

(4)两个主机要进行通信,不仅要知道对方的IP地址,而且还要知道对方的端口号,分别对应的就是对方的主机和对方主机内的应用进程。

(5)UDP的主要特点是:a、无连接。b、尽最大努力交付。c、面向报文。d、无拥塞控制。e、支持一对一、一对多、多对一和多对多交互通信。f、首部开销小,只有四个字段:源端口、目的端口、长度、检验和。

(6)TCP的主要特点是:a、面向连接。b、每条TCP连接只能是点对点的(一对一)。c、提供可靠交付的服务。d、提供全双工通信。e、面向字节流。

(7)TCP用主机的IP加上端口号作为TCP连接的端点,这样的端点就是套接字(socket)或插口,套接字的表示是(IP地址:端口号),每一条TCP连接唯一地被通信两端的两个端点(两个套接字)所确定,即TCP连接::={socket1,socket2}={(IP1:port1),(IP2:port2)},同一个IP地址可以有多个不同的TCP连接,同一个端口号也可以出现在多个不同的TCP连接中。

(8)停止等待协议能够在不可靠的传输网络上实现可靠的通信,每发送完一个分组就停止发送,等待对方的确认,在收到确认之后在发送下一个分组,分组需要进行编号,停止等待协议中,如果接收方收到重复分组,丢弃该分组,但是依然要发送确认。

(9)超时重传是说的只要过了一段时间仍然没有收到确认,那么就重传前面发送过的分组(默认前面分组已丢失)。因为每发送完一个分组要设置一个超时计时器,其重传时间比数据在分组传输的平均往返时间更长一些,这个称为自动重传请求ARQ。

(10)连续ARQ协议可提高信道利用率,发送方维持一个发送窗口,位于发送窗口内的分组可连续发送出去,不需要等待对方的确认,接收方一般采用累积确认,就是对按序到达的最后一个分组发送确认,表明到这个分组为止的 所有分组都正确收到了。

(11)TCP报文段首部的前20个字节是固定的,后面的4N字节是根据需要而增加的选项(N为整数)。在一个TCP连接中传送的字节流中的每一个字节都按照顺序编号,手不中的序号字段值指的是本报文段所发送的数据的第一个字节的序号。而TCP首部中的确认号是期望收到的对方下一个报文段的第一个数据字节的序号。若确认号为N,表示到序号N-1为止的所有数据正确接收,首部中的窗口字段指出了现在允许对方发送的数据量,并且窗口值一般是在动态变化的。

(12)TCP采用滑动窗口机制。发送窗口里面的序号表示允许发送的序号。发送窗口后沿的后面部分表示已发送且已收到确认,发送窗口的前沿的前面部分表示不允许发送的。发送窗口后沿的变化情况有两种,一是不动(没有收到新的确认)和前移(收到了新的确认)。发送串口前沿通常不断向前移动。

(13)拥塞是指某段时间对网络中的某一资源的需求超过了该资源所能提供的可用部分,网络性能就会变坏,拥塞控制就是防止过多的数据注入到网络中,这样可以使网络中的路由器或者链路不至于过载。

(14)流量控制是一个端到端的问题,是接收端抑制发送端发送数据的速率,以便使接收端来得及接收。TCP协议中,发送方让自己的发送窗口取拥塞窗口和接收方接收窗口中较小的一个。

(15)TCP的拥塞控制采用了四种算法,慢开始、拥塞避免、快重传、快恢复。在网络层,也可以采用使路由器适当的分组丢弃策略(随机早期检测RED),以减少网络拥塞的发生。

(16)TCP的三个过程:连接建立(三次握手)、数据传送、连接释放(四次握手)。

(17)主动发起TCP连接建立的应用进程叫做客户,被动等待连接建立的应用进程叫做服务器。TCP的连接建立采用三次握手机制。服务器要确认客户的连接请求,然后客户要对服务器的确认进行确认。

(18)TCP的连接释放采用四次握手机制。任何一方都可以在数据传送结束后发出连接释放通知,待对方确认之后就进入半关闭状态。另一方也没有数据再发送时,就发送连接释放通知,对方确认之后就完全关闭了TCP连接。

            运输层是面向通信部分的最高层,同时也是用户功能中的最底层,只有主机的协议栈才会有运输层,网络核心的路由器在转发分组时都只用到了下三层的功能。IP数据报已经能够正确送到主机,但是通信的实体是主机中的进程,运输层就是将其送往相应的端口,为应用进程之间提供端到端的逻辑通信。所以对于同一个主机接收到的多个数据报或者发送来自多个主机的多个数据报,运输层就体现出了它的复用和分用的能力,将数据报交给不同的进程,不同的进程的数据报都可以通过运输层协议传送。并且运输层还要对收到的报文进行差错检验,IP数据报首部中的检验和字段,只会检验首部不检验数据部分。

            根据应用程序的不同需求,运输层采用两种不同的运输协议:TCP/UDP(传输控制协议/用户数据报协议),按照OSI的术语,通信时产生的数据单位叫做运输协议数据单元TPDU,但是根据采用的不同协议,分别称为TCP报文段和UDP用户数据报,两种协议的差异是:UDP不需要首先简历连接,接收到数据之后也不需要进行任何确认。TCP传送数据前要先进行连接,数据传送结束之后释放连接,不能提供广播或者多播服务,因为要确认、流量控制、计时器、连接管理等,使数据单元的首部增加了很多,占用了许多的处理机资源。

下图介绍下哪些使用了UDP,哪些使用了TCP。


一、UDP概述

               UDP其实只是在IP数据报服务上增加了很少的功能,就是复用和分用以及差错检测。上文说了UDP是面向报文的,具体来讲就是说UDP对于应用层交下来的报文,添加首部之后就向下交付IP层,既不合并、也不拆分,而是保留这些报文的边界。对于IP层接收到的UDP用户数据报,在去除首部之后就原封不动交给上层的应用进程,也就是说UDP一次交付一个完成的报文,因此应用程序需要选择合适的大小,否则太长IP层会进行分片,太短IP数据报的首部相对长度就太大,都会降低IP层的效率,下图可以看到UDP如何交付给IP层:


            上文也说过UDP是没有拥塞控制,这就代表了网络拥塞并不会使它的发送速度降低,这也是某些实时应用所需要的,例如电话和视频,要主机以恒定速率发送数据,丢失一部分数据没关系,但是不能有太大时延。

相对于TCP20个字节的首部,UDP的首部只有八个字节四个部分,每个部分都是两个字节,下面介绍UDP的首部格式:
 (1)源端口:在需要对方回信时选用,不需要为全0;
 (2)目的端口:在终点交付报文时必须要使用的;
 (3)长度:UDP用户数据报的长度,最小值为8(仅有首部);
 (4)检验和:检验UDP用户数据报在传输中是否有错,有错就丢弃;
             

              如果接收方UDP发现接收到的报文的目的端口号不对,即不存在对应于该端口号的应用进程,就丢弃该报文,并回复端口不可达差错报文给发送方。UDP用户数据报的检验和的计算方式有点特殊,需要在数据报前面加上12个字节的伪首部再进行计算,这个伪首部只是计算的时候临时添加的,既不想上也不向下传递,仅仅为了计算检验和,UDP数据报的检验和计算和IP数据报类似,但是不同的是IP数据报只检验首部,但是UDP需要把数据和首部一起检验,这种差错检验方法检错能力不强,但是计算简单快捷,这里就不介绍了。当接收到差错报文时,选择丢弃这个报文,或者交给应用层,但是附上出现差错的警告,下图是UDP用户数据报的首部和伪首部:


二、TCP概述
比起UDP,TCP多了许多特点,上面已经讲过,下面就详细解释一下:
(1)面向连接:就是必须先建立连接,输出传送结束再释放连接,就好像打电话一样。
(2)一对一,每一条连接智能有两个端点。
(3)可靠交付,通过TCP传送的数据,无差错、不丢失、不重复、按序到达。(感觉这几句话好像金坷垃。。。)
(4)全双工通信。允许通信双方的应用进程随时发送数据,TCP两端都是发送缓存和接收缓存,用来临时存放双方通信的数据,发送时,应用程序把数据传送给TCP缓存之后,就可以干自己的事了,TCP在合适的时候发送,接收时,TCP把接收到的数据放入缓存,上层的应用进程在合适的时候读取其中的数据。
(5)面向字节流,虽然应用程序和TCP交互连串的无结构的字节流,但TCP不知道字节流的具体意义,也不保证发送进程给的数据块和接收到的数据块数目一致,也就是说TCP会对接收到的数据块进行重新组合,可能变多也可能变少,但是字节流内部的数据肯定是完全一样的。

因为要保证是可靠传输的工作原理,那么需要满足两个条件才能保证可靠传输:
(1)传输信道不产生差错:TCP采用一些可靠的传输协议,当出现差错的时候让发送方重新传送出现差错的数据。
(2)不管多快的速度发送数据,接收方总是来得及处理接收到的数据:TCP在接收方来不及处理时,会及时告诉发送方降低发送速度。


下面就来讲解一下几个协议:

停止等待协议

             介绍下最简单的停止等待协议,运输层并不采用该协议,不过该协议面对的问题和运输层想要完成可靠运输面对的问题是一样的。该协议说的是A发送一个分组M1,发完之后暂停发送,等待B的确认。B收到了M1之后就朝A发送确认,A收到了对M1的确认之后在发送下一个分组M2,正常情况下就这样一直进行下去。

           但是现实中肯定会有意外情况的,比如B在接收到M1时检测到出了差错,B直接丢弃M1(不会通知给A),或者M1在传输过程中丢失了,结果和上一种情况一样,可靠传输协议是这样设计的,A只要过了一段时间没受到确认,就认为分组丢失,直接重传之前的分组,这个就是超时重传,所以每发送一个分组,都会设置一个超时计时器,在到期前收到确认就撤销该计时器,所以A发送完一个分组之后,必须暂时保留已发送的分组的副本,只有收到确认之后才能清楚该副本;分组和确认分组都必须编号,这样才能分清楚是哪一个分组和哪个分组的确认;超时计时器必须比数据在分组传输的平均往返时间更长一点,一般动态的设置这个计时时间。那假如B发送的确认丢失了,第二次收到相同的分组怎么办呢:B直接丢弃这个分组,再次向A发送确认,因为A就是因为没收到确认才会重传的,因为A就算收到了重复的确认,收下后也就直接丢弃了。通过上述的确认和重传机制,就实现了在不可靠的传输网络上的可靠的通信,所以称上述这种可靠传输协议为自动重传请求ARQ。

          但是如果一次只是传输一个分组,然后等待确认,这样新到的利用率特别低,绝大多数时间是空闲的,信道利用率大概在5%以下,所以发送方采用一种新的流水线传输方式,连续发送多个分组,下面介绍这个连续ARQ协议和滑动窗口协议。

         连续ARQ协议就是维持一个大于1的发送窗口,将发送窗口内的分组都可以连续发送出去,发送方每收到一个确认,就把发送窗口往前移动到相应的位置,因为接收方采用的是累积确认的方式,对按序到达的最后一个分组发送确认,所以发送方收到确认后,再看应该将发送窗口前移几位。累积确认是有一定的优点的:容易实现,即使传送的确认丢失了,但是因为后面的确认会告诉发送方前面的收到了,所以丢失也没有必要重传。缺点就是在漏序的情况不能反映出接收方正确收到的所有分组信息,会重复传送这就叫做Go-back-N现象。

下面记录TCP的报文了,首先是TCP的首部格式,其中20个字节固定,后面有4n字节是根据需要而增加的:
(1)源端口和目的端口,各占两个字节
(2)序号(报文段序号),四个字节。循环使用,[0,2^32-1],TCP是面向字节流的,在TCP中的每一个字节都按照顺序编号。整个传送的字节流的起始序号在连接建立时设置,首部中的序号字段值指的是本报文段发送数据第一个字节的序号,例如,本报文段第一个字节为100,携带数据100,那最后一个字节的序号就是199,并且,下一个报文段的序号从200开始。
(3)确认号,四个字节,期望收到对方下一个报文段的第一个数据字节的序号,若确认号为N,代表到序号N-1的所有数据已经正确收到,因为序号字段4个字节,就算是循环使用,新的序号使用的时候,旧的序号应该早就通过网络到达终点了。
(4)数据偏移,四位,指出TCP报文的数据起始处距离TCP报文段的起始处有多远。起始就是指出TCP报文段的首部长度,因为手不中有长度不确定的选项字段,数据偏移能表示最大的数是15,它的单位是32位字(就是四个字节长的字),所以他能表示最大60字节,这也是TCP首部的最大长度。
(5)保留字,6位,保留为今后使用,目前为0;
(7)紧急URG,当其为1,相当于高优先级数据,配合紧急指针字段使用,表明紧急指针字段使用有效。
(8)确认ACK,只有它为1时,确认字段才有用,TCP规定,当连接建立之后,所有传送的报文段都必须把AVK置为一。
(9)推送psh
(10)复位RST、同步SYN(当它为1,ACK为0,代表这是一个连接请求报文,若对方同意连接,应该在响应报文中让SYN和ACK都为1)、终止FIN(为1代表发送方的数据发送完,要求释放运输链接)
(11)窗口,两个字节,指发送本报文段的接收窗口(不是发送窗口)。窗口值告诉对方:从本报文的确认号算起,接收方目前允许对方发送的数据量,因为双方的缓存空间有限,所以窗口值是接收方让发送方设置其发送窗口的依据,窗口值一般是动态变化着的。
(12)检验和,两个字节,检验首部和数据两部分,同样在检验时前面要加上12个字节的伪首部。
(13)紧急指针,2字节,仅在URG=1有效,指出紧急数据的字节数。窗口为0也可发送。
(14)选项,长度可变,最多40字节。


TCP的可靠传输实现靠的是以字节为单位的滑动窗口、超时重传(时限的选择采用自适应算法)、选择确认(漏接收时候使用,大多数时候的实现还是采用重传所有未被确认的数据块)。


因为TCP利用滑动窗口实现流量控制,所以TCP设置了一个持续计时器,只要TCP一方收到对方的零窗口通知,就启动计时器,设置时间到期后,发送一个字节数据的零窗口探测报文,如果确认报文范围依然是0,重新设置计时器,否则就开始传送。
TCP还有拥塞控制,太多了,下一次有时间在写。

TCP的运输连接管理
连接的建立过程要解决三个问题:
(1)每一方知道对方存在。
(2)允许双方协商一些参数。
(3)能够对运输实体资源进行分配。
因为TCP只能一对一,所以采用客户服务器方式,主动发起连接的叫客户,被动等待连接的叫服务器。
三次握手的示意图如下所示:

(1)最开始AB都处于close状态,A主动打开连接,B被动打开连接。B的TCP服务器进程先创建传输控制块TCB,准备接收客户进程的连接请求,然后服务器处于listen状态,等待客服的连接请求,如果有就做出响应。

(2)A的TCP客户进程也是先创建传输控制块TCB,然后向服务器B发出连接请求报文,这时报文首部中的同部位SYN=1,同时选择一个初始序列号 seq=x ,此时,TCP客户端进程进入了 SYN-SENT(同步已发送状态)状态。TCP规定,SYN报文段(SYN=1的报文段)不能携带数据,但需要消耗掉一个序号。

(3)TCP服务器B收到请求报文后,如果同意连接,则向A发出确认报文。确认报文中应该设置 ACK=1,SYN=1,确认号是ack=x+1,同时也要为自己初始化一个序列号 seq=y,此时,TCP服务器进程进入了SYN-RCVD(同步收到)状态。这个报文也不能携带数据,但是同样要消耗一个序号。

(4)A的TCP客户进程收到确认后,还要向服务器B给出确认。确认报文的ACK=1,ack=y+1,自己的序列号seq=x+1,此时,TCP连接建立,客户端进入ESTABLISHED(已建立连接)状态。TCP规定,ACK报文段可以携带数据,但是如果不携带数据则不消耗序号,这这种情况下,下一个数据报文段的序号仍然是seq=x+1;

当服务器收到客户端的确认后也进入ESTABLISHED状态,此后双方就可以开始通信了,这就是三次握手的全部了。

为什么TCP客户端最后还要发送一次确认呢?
          主要防止已经失效的连接请求报文突然又传送到了服务器B,从而产生错误。如果使用的是两次握手建立连接,假设有这样一种场景,客户端发送了第一个请求连接并且没有丢失,只是因为在网络结点中滞留的时间太长了,由于TCP的客户端迟迟没有收到确认报文,以为服务器没有收到,此时重新向服务器发送这条报文,此后客户端和服务器经过两次握手完成连接,传输数据,然后关闭连接。此时此前滞留的那一次请求连接,网络通畅了到达了服务器,这个报文本该是失效的,但是,两次握手的机制将会让客户端和服务器再次建立连接,这将导致不必要的错误和资源的浪费。如果采用的是三次握手,就算是那一次失效的报文传送过来了,服务端接受到了那条失效报文并且回复了确认报文,但是客户端不会再次发出确认。由于服务器收不到确认,就知道客户端并没有请求连接。

TCP连接的释放(四次握手)
四次握手的示意图如下所示:

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

(2)A客户端进程首先发出连接释放报文,并且停止发送数据,主动关闭TCP连接。A把连接释放数据报文首部的FIN=1,其序列号为seq=u(等于前面已经传送过的数据的最后一个字节的序号加1),此时,客户端A进入FIN-WAIT-1(终止等待1)状态,等待B的确认。 TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。

(3)服务器B收到连接释放报文,发出确认报文,其中ACK=1,ack=u+1,并且带上自己的序列号seq=v,它等于B前面已传送过的数据的最后一个字节的序号加1.此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP服务器进程这时因通知高层的应用进程,客户端A向服务器B的这个方向的连接释放了,这时候处于半关闭状态,即客户端A已经没有数据要发送了,但是服务器B若发送数据,客户端A依然要接受,也就是说从B到A这个方向的连接并未关闭。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。

(4)客户端A收到服务器B的确认请求后,此时,客户端A就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。

(5)若服务器B将最后的数据发送完毕后,其应用进程就通知TCP释放连接。B就向客户端A发送连接释放报文,此报文必须是FIN=1,还必须重复上次已经发送过的确认号ack=u+1,由于在半关闭状态,服务器B很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器B就进入了LAST-ACK(最后确认)状态,等待客户端A的确认。

(6)客户端A收到服务器B的连接释放报文后,必须发出确认,确认报文中ACK=1,ack=w+1,而自己的序列号是seq=u+1(根据TCP标准,前面发送的FIN报文段要消耗一个序号),此时,客户端A就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过时间等待计时器(TIME_WAIT timer)设置的2∗MSL(最长报文段寿命)的时间后,A才进入到CLOSED状态,MSL是最长报文段寿命,规定设置两分钟,但是允许设置更小。因此A进入TIME-WAIT状态后,要四分钟之后进入CLOSED状态,才能开始建立下一个新的连接,当A撤销相应的传输控制块TCB之后,就结束了这次TCP连接。


(7)服务器B只要收到了客户端A发出的确认,立即进入CLOSED状态。同样,B撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。

为什么客户端最后还要等待2MSL(Maximum Segment Lifetime)?
            第一,保证客户端A发送的最后一个ACK报文能够到达服务器,因为这个ACK报文可能丢失,站在服务器的角度看来,我已经发送了FIN+ACK报文请求断开了,客户端还没有给我回应,应该是我发送的请求断开报文它没有收到,于是服务器又会重新发送一次,而客户端就能在这个2MSL时间段内收到这个重传的报文,接着给出回应报文,并且会重启2MSL计时器,如果直接关闭,就无法收到重传的FIN+ACK报文段,B无法按照正常步骤进入CLOSE状态。
            第二,防止类似与“三次握手”中提到了的“已经失效的连接请求报文段”出现在本连接中。客户端发送完最后一个确认报文后,在这个2MSL时间中,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样在新的连接中不会出现旧连接的请求报文。

为什么建立连接是三次握手,关闭连接确是四次挥手呢?
             建立连接的时候, 服务器在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。 而关闭连接时,服务器收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,而自己也未必全部数据都发送给对方了,所以己方可以立即关闭,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送,从而导致多了一次。

如果已经建立了连接,但是客户端突然出现故障了怎么办?
              TCP还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75分钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!