七层模型之运输层

运输层与网络层

  当网络边缘部分中的两个主机使用网络的核心部分的功能进行端到端的通信时,只有主机的协议栈中才有运输层,而路由器在转发分组时只用到下三层的功能。
  对于网络IP层来说。通信的是两个主机,IP数据报表明了这两个主机的IP地址,但实质上,应该是两个主机上的进程之间的通信,而运输层就是实现主机上的应用进程之间的通信的。也就是说。通信的真正端点不是主机,而是主机上的应用进程。网络层是为主机之间提供逻辑通信,而运输层是为应用进程之间提供端到端的逻辑通信。
  在网络层,IP数据报首部中的检验和字段,只检验首部是否出现差错而不检查数据部分。运输层还要对收到的报文进行差错检测。

逻辑通信的意思是:运输层之间通信好像是沿着水平方向传送数据,但事实上这两个运输层之间并没有一条水平方向的物理连接,要传送的数据是按照模型层次进行传送的。

运输层的功能

运输层最主要的两个功能就是复用和分用

  复用:是指在发送方不同的应用进程可以使用同一个运输层协议传送数据(当然需要加上适当的首部)。
  分用:是指接收方的运输层在剥去报文的首部之后能够把这些数据正确的交付到目的应用进程。

  运输层还要对收到的报文进行差错检测。根据应用程序的不同需求,运输层需要有面向连接的TCP和无连接的UDP协议
  运输层向高层用户屏蔽了下面网络核心的细节(如网络拓扑,所采用的路由选择协议等),它使用用进程看见的好像就是两个运输层实体之间有一条端到端的逻辑通信信道,这条信道对上层的表现却因运输层使用不同的协议而有很大的差异。当运输层采用的是面向连接的TCP协议时,尽管下面的网络是不可靠的,但是这种逻辑通信信道就相当于一条全双工的可靠通信信道。当运输层使用无连接的UDP协议时,这种逻辑信道就是一条不可靠的信道。

运输层的端口

  端口对于运输层来说非常重要,IP地址唯一标识一个主机,而IP地址+端口则唯一标识一个主机上的一个应用进程,才能实现端到端的通信。
  但是,虽然通信的终点是应用进程,但只要传送的报文交到目的主机的某一合适的目的端口,剩下的最后交付给目的进程的工作就交给TCP来完成。端口号的本意是标志本计算机应用层中的各个进程在和运输层进行交互时的层间接口。在因特网中,不同计算机中的相同端口号是没有关联的。

软件端口和硬件端口
  硬件端口是不同的硬件设备进行交互的接口。
  软件端口是应用层的各种协议进程与运输实体进行层间交互的一种地址。

部分应用程序以及熟知端口号(前四个使用TCP,后四个使用UDP):

FTP:21  TELENT:23  SMTP:25  HTTP:80
TFTP:69  DNS:53  SNMP:161  SNMP(trap):162

UDP与TCP

  UDP在传送数据之前不需要先建立连接,远程主机的运输层收到UDP数据报之后,不需要给出任何确认提供广播和多播服务
  TCP在传送数据之前需要先建立连接,远程主机的运输层收到TCP报文之后,需要给出确认信息。断开连接时需要释放连接不提供广播和多播服务。由于要提供可靠的面向连接的服务,如确认,流量控制,计时器以及连接管理等,所以需要增加开销,占用更多的处理机资源

用户数据报协议UDP

 udp是无连接的,不可靠的协议。面向报文,发送端的UDP对应用程序交下来的报文,在添加首部后就向下交付给IP层,也就是说UDP对于应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界。应用层交给UDP多长的报文,UDP就照样发送,即一次发送一个报文。在接收端的IP层数据报传递给网络层时,UDP在去除首部后就原封不动地交给上层的应用进程。
 UDP没有拥塞控制,首部开销小,只有8字节,而TCP首部有20个字节。UDP会计算校验和,其方法与IP数据报基本相似,但是IP数据报只对首部进行检验,而UDP的检验和是把首部和数据部分一起都检验。
   以下是UDP的首部格式:
七层模型之运输层
 1.源端口
 2.目的端口
 3.长度:UDP用户数据报的长度,其最小值是8字节
 4.检验和:检验UDP用户数据报在传输中是否有错。有错就丢弃。

传输控制协议TCP

 
  TCP是面向连接的运输层协议,每一条TCP连接只有两个端点,每一条TCP连接只能是点对点的,TCP提供全双工的通信,通信双方可以的应用进程在任何时候都能发送数据。TCP是面向字节流的。  

TCP的全双工的含义:
  通信双方可以的应用进程在任何时候都能发送数据,TCP连接的两端都设有发送缓冲和接收缓冲,用来临时存放双向通信的数据,在发送时,应用程序在把数据传送给TCP缓存后,就可以去做自己的事情了,而TCP在合适的时候把数据发送出去。在接收时,TCP把接收到的数据放入缓存,上层的应用进程在合适的时候读取缓存中的数据。

TCP的面向字节流的含义:
  “流”是指流入到进程或从进程流出的字节序列。“面向字节流”的含义是:虽然应用程序和tcp的交互是一次一个数据块,但TCP把应用程序交下来的数据看成是仅仅是一连串的无结构的字节流。TCP并不知道所传送的字节流的含义,TCP不保证接收方应用程序所收到的数据块和发送方的应用程序发送的数据块具有对应大小的关系(也就是发送方的应用程序交给发送方的TCP一共10个数据块,但接收方的TCP可能只用了4个数据块就把收到得字节流交付给了接收方的应用程序)。但接收方应用程序收到的字节流必须和发送方的应用程序发出的字节流完全一样,当然,接收方的应用程序必须有能力识别收到的字节流,把它还原成有意义的应用层数据。

  TCP根据对方给出的窗口值和当前网络的拥塞程度来决定一个报文段应包含多少个字节,而UDP的报文长度是应用进程给出的。

TCP的连接

  前面提到,TCP连接是端到端的,但这个端不是指主机,不是主机的IP地址,也不是应用进程,更不是运输层的端口,它是套接字或插口,根据RFC定义:端口号拼接到IP地址即构成了套接字,所以套接字的表示方法就是点分十进制的IP地址后面写上端口号,中间用冒号或逗号隔开,即
      套接字socket=(IP地址:端口号)
  每一条TCP连接唯一地被通信两端的两个端点(即两个套接字)所确定。TCP连接的端点是套接字,同一个IP地址可以有多个不同的tcp连接,同一个端口号也可以出现在多个不同的tcp连接中。

同一个名词socket可能有不同的意思:
 1.允许应用程序访问的连网协议的应用编程接口API,即运输层和应用层之间的一种接口,成为socket API,简称socket。
 2.在socket API中使用的一个函数叫做socket。
 3.调用socket函数的端点成为socket,如创建一个数据报socket。
 4.调用socket函数时,其返回值称为socket描述符,简称socket。
 5.在操作系统内核中连网协议的Berkeley实现,称为socket实现。
这些socket的意思与上述所引用的RFC所定义的socket不同。

TCP报文段的首部格式

  TCP虽然面向字节流,但传送的数据单元却是报文段。一个TCP报文段包含首部和数据两部分。首部中包含了TCP的所有功能。
  TCP报文段前20个字节是固定的,后面的4N字节是根据需要增加的选项。
  首部固定各字段的意义如下:
  1.源端口和目的端口:各占2字节,TCP的分用功能也是通过端口实现的。
  2.序号:占4字节,序号范围是0~2^32-1,在到达上限之后,又变回0,在一个TCP连接中传送的字节流中的每一个字节都是按顺序编号。
  3.确认号:占4字节,是期望收到对方下一个报文段的第一个数据字节的序号。如B正确的收到了A发送过来的序号字段为501的报文段,该报文段长度为100,那么这表明B收到了A发送的到序号600为止的数据,因此,B期望收到A的下一个数据序号为601,于是B在发送给A的确认报文段中把确认号置为701。
  4.数据偏移:实际上是指TCP首部的实际长度。占4字节。
  5.保留:占6位,保留为今后使用。
  6.紧急URG:意思是当值为1时,该数据具有较高优先级,需紧急传送,不要按原来的顺序来传送。
  7.确认ACK:当ack值为1时有效,TCP规定,在连接建立后所有传送的报文段都必须把ack置为1。
  8.推送PSH:用于应用进程执行一个命令需要立即收到对方响应,TCP就进行此操作,发送方将PSH置为1,并立即创建一个报文段发送出去,接收方收到之后,就尽快交付给应用进程,而不等待整个缓存被填满后再向上交付。
  9.复位RST:值为1时,表示TCP连接中出现严重错误,必须释放连接,重新建立连接,也可以用来拒绝一个非法报文段或拒绝打开一个连接。
  10.同步SYN:在连接时用来同步序号。当SYN=1,ACK=0时,表明这是TCP连接请求报文。对方同意建立连接之后,应在相应报文中使得SYN=1,ACK=1。因此,SYN置为1就表示这是一个连接请求或连接接受报文。
  11.终止FIN:用来释放一个连接,当FIN=1时,表明此报文段发送方的数据已经发送完毕,并要求释放运输连接。
  12.窗口:占2字节,窗口范围为0~2^16-1之间的整数。窗口指发送本报文段的一方的接收窗口。窗口值告诉对方:从本报文段首部中的确认号算起,接收方目前允许对方发送的数据量。因为接收方的数据缓存空间有限。窗口字段明确指出了现在允许对方发送的数据量,且窗口值是动态变化的。
  13.检验和:占2字节,检验范围包括首部和数据。
  14.紧急指针:占2字节,仅在URG=1时有意义,即使窗口为0也可发送紧急数据。
  15.选项:长度可变。最长可达40字节。
  MSS:是指每一个TCP报文段中的数据字段的最大长度。默认是536字节。其意义在于使的网络利用率较高,不至于浪费网络资源,并且在IP层能够不进行分片。
  时间戳:占10字节,该选项有两个功能:
  1.用来计算往返时间RTT:发送方发送报文时把当前时间放入时间戳字段,接收方在确认该报文段时把时间戳字段值复制到时间戳回送回答字段。
  2.用于处理TCP序号超过2^32的情况,这又称为防止序号绕回。为了使接收方把新的报文段和迟到很久的报文段分开,可以在报文段中加上这种时间戳。
七层模型之运输层

可靠传输的工作原理

  使用一些可靠传输协议,当出现差错时让发送方重传出现差错的数据,同时在接收方来不及处理收到的数据时,及时告诉发送方适当降低发送数据的速度。

停等协议:

   就是每发送完一个分组就停止发送,等待对方的确认。在收到确认后再发送下一个分组。
   1.出现差错情况
    当出现差错后,接收方什么也不做,可靠传输协议的做法是:只要发送方一段时间后仍然没有收到确认,就认为刚才发送的分组丢失了,因而重传前面发送的分组,这就叫做超时重传。这就要在每发完一个分组就设置一个超时计时器。
    所以,在发完一个分组之后,还需要保留已发送的分组的副本,为发生超时重传时使用。只有收到相应的确认后才能清除暂时保留的分组副本和超时计时器。此外,分组和确认分组都必须进行编号。超时计时器设置的重传时间应该比数据平均往返时间更长一些。
   2.确认丢失和确认迟到
    对于这种差错,可以采取两个行动:1.丢弃这个重复的分组,不向上层交付;2.向发送方发送确认。不能认为已经发送过确认就不再发送,因为发送方之所以重传就是因为没有收到确认。这种重传请求是自动的,接收方不需要请求发送重传某个出错的分组。像这种可靠的传输协议就称为自动重传请求ARQ。    

连续ARQ协议:

   发送方每收到一个确认,就把发送窗口向前滑动一个分组的位置,如果原来已经发送了前5个分组,那么现在就可以发送窗口内的第6个分组了。
   接收方一般采用累积确认的方式,这就是说,接收方不必对收到的分组逐个发送确认,而是可以在收到几个分组之后,对按序到达的最后一个分组发送确认,这样就表示:到这个分组为止的所有分组都已经正确收到了。

TCP可靠传输的实现

 以字节为单位的滑动窗口:

   在发送的数据中,可能存在:

已发送并收到确认的数据【接收方期望收到的序号,(将该位置标为p1)】已发送但待确认的数据的序号【将该位置标为p2】待发送待确认的数据的序号【将该位置标为p3】目前不允许发送数据,也即未发送数据  

  在以上标注的p1~p3的长度为发送窗口的大小,p1端为发送窗口的后沿,p3为发送窗口的前沿。发送缓存的起始位置在p1。
  发送窗口的后沿有可能不动也有可能前移,不动可能是因为没有收到新的确认,前移可能是因为收到了新的确认。(P1处接收方期望收到的序号就是接收方发来的确认号)。当然发送窗口的前沿也有可能后缩,这是因为对方通知的窗口缩小了,但这一般TCP标准是不赞成的。
  当发送方正常收到接收方的确认号时,发送窗口就向后移动,长度不变,p1的位置就移动到了确认号的数据号的位置,当p2与p3重合,就说明待发送数据已经发送完毕,还没有收到确认号,此状态下发送窗口处于满的状态,因此必须停止发送。但接收方极有可能是因为确认帧在网络中阻塞,这时,发送方在经过超时时间之后就会重传发送窗口中的数据,直到收到接收方的确认为止。如果发送方收到的确认号落在了发送窗口中,那么发送窗口就可以继续向前滑动,并发送新数据了。
  在接收的数据中,可能存在:

已收到并正在被应用程序读取的数据【将该位置标为p1】按序到达的但还未被应用程序读取的数据【接收方下一个期望收到的字节,(将该位置标为p2)】未按序到底的数据【将该位置标为p3】  

  接收窗口的起始位置在p2~p3的位置,而接收缓存在p1~p3的位置,因为应用程序还没有读取到p1~p2之间的数据,虽然数据已经按序到达。

发送缓存用来暂时存放:
 1.发送应用程序传送给发送方TCP准备发送的数据;
 2.TCP已发送出但尚未收到确认的数据;
 发送窗口通常只是发送缓存的一部分,已经被确认的数据应当从发送缓存中删除,因此发送缓存和发送窗口的后沿是重合的,发送应用程序最后写入发送缓存的字节减去最后被确认的字节,就是还保留在发送缓存中的被写入的字节数,发送应用程序需要控制写入发送缓存的速率,以避免发送缓存满。
接收缓存用来暂时存放:
 1.按序到达的,但尚未被接收应用程序读取的数据;
 2.未按序到达的数据;
 如果收到的分组被检测出有差错,就要丢弃,如果接收应用程序来不及读取收到的数据,接收缓存将会被填满,使得接收窗口为0,接收窗口的大小不能超过接收缓存的大小,其中下一个期望收到的字节号就是接收方给发送方的报文段的首部中的确认号。

  虽然发送方的发送窗口是根据接收方的接收窗口来设置的,但在同一时刻,发送方的发送窗口并不总是和接收方的接收窗口一样大,因为通过网络传送的窗口值需要经历一定的时间滞后,而这个时间是不确定的。
  对于未按序到达的数据应该如何处理,TCP通常是先临时存在接收窗口中,等到字节流中缺少的字节收到后,再按序交付给上层应用程序。
  TCP要求接收方必须有累积确认的功能,接收方可以在合适的时机发送确认,也可以在自己有数据要发送时捎带把确认信息发送给发送方。
  对于那些没有出错,但是部分数据未按序到达而使得数据不得不进行全部重传的数据其实可以通过选择确认SACK来规定,对于未按序到达的数据,只需要重传还没有到达的数据序号就可以了,不过这就要增加TCP头部的SACK选项,并且规定传送边界,所以大多数的实现还是重传所有未被确认的数据块。

TCP的流量控制

  流量控制就是让发送方的发送速率不要太快,要让接收方来得及接收。

 利用滑动窗口实现流量控制:

  发送方的发送窗口不能超过接收方给出的接收窗口的数值。在连接建立的时候,接收方就会告诉发送方自己的接收窗口大小。
  七层模型之运输层
  (起初B告诉A它的接收窗口大小是400,上图进行了3次流量控制)
  有一个问题就是,倘若B向A发送了零窗口报文,B的接收缓存有了一些存储空间之后向A发送了非零窗口报文,但在传输过程中丢失了,就会出现A一直等待B的通知,而B也在等待A发送数据。为解决这个问题,TCP为每一个连接设置了一个持续计时器,只要TCP连接的一方收到对方的零窗口通知,就启动持续计时器,若计时器时间到,就发送一个零窗口探测报文段,而对方就在确认这个探测报文段时给出现在的窗口值,如果窗口仍然是0,那收到报文的一方就重新设置持续计时器,如果窗口不是0,那么死锁的僵局就被打破。

TCP的拥塞控制

 拥塞控制与流量控制:

  拥塞控制是防止过多的数据注入到网络中,这样可以让网络中的路由器或者链路不至于过载。是一个全局的过程。而流量控制是点对点的通信,只要是通过接收端的接受窗口大小来控制发送端的发送窗口的大小,以控制发送速率,是一个端到端的问题。也就是说两者侧重点不同,流量控制注重两端,而拥塞控制着眼于网络传输中的拥塞问题。

几种拥塞控制方法:

  包括慢启动,拥塞避免,快重传以及快恢复

发送方维持一个叫做拥塞窗口的状态变量,拥塞窗口的大小取决于网络的拥塞程度。并且动态变化,发送方让自己的发送窗口的大小等于拥塞窗口,如果再考虑接收方的接收能力,那么发送窗口还可能小于拥塞窗口。只要网络没出现拥塞,那么拥塞窗口就再增大,拥塞了,就减小一点。
 当网络发生拥塞,路由器就丢弃了分组,所以只要发送方没有按时收到应当到达的确认报文,发送方就猜想可能出现了网络拥塞。

慢启动算法:

  先探测一下,由小到大逐渐增大发送窗口,即由小到大逐渐增加拥塞窗口数值,刚开始先把拥塞窗口cwnd设置为一个最大的报文段MSS的数值,每收到一个对新的报文段的确认后,把拥塞窗口增加至多一个MSS的数值,用这样的方法逐步增大发送方的拥塞窗口cwdn,可以使得分组注入到网络的速率更加合理。

拥塞避免算法:

 为防止拥塞窗口过大引起网络拥塞,需要设置一个慢启动门限值ssthresh状态变量,
 当拥塞窗口cwnd小于ssthresh,启动慢启动算法;
 当cwnd>ssthresh,停止慢启动改为拥塞避免算法;
 当cwnd=ssthresh时,两个算法都可以。
 拥塞避免是说让拥塞窗口缓慢增大,每经过一个RTT就将发送方的拥塞窗口cwnd加1,而不是加倍,这样,拥塞窗口cwnd按照线性规律缓慢增长,比慢启动算法的拥塞窗口增长速率缓慢得多。
 但无论是慢启动阶段还是拥塞避免阶段,只要发送方判断出现了网络拥塞,那么门限值就设置为出现拥塞时的发送窗口的一半。之后将拥塞窗口重新设置为1,进行慢启动阶段。以迅速减少网络中的分组。

快重传和快恢复算法:

  快重传算法是说在接收方收到失序的报文段时,按照本来的规则是接收方等待合适时机发送对失序前的未失序报文的确认,但快重传算法的策略就是一旦收到失序报文,就立即发出重复确认,当发送方一连收到三个重复确认就应当立即重传对方尚未收到的报文段,而不必等待缺失报文的重传计时器到期。即尽早重传未被确认的报文段。
  快恢复算法是说,当发送方连续收到三个重复确认的报文段时,启动“乘法最小”算法,将慢启动门限值减半。并将拥塞窗口设置为减半后的慢启动门限值,然后开始执行拥塞避免算法(“加法增大”)。
  在采用快恢复的算法中,慢启动算法只有在建立TCP连接或者超时时使用。

TCP的连接及释放

 TCP状态转换图:
 七层模型之运输层
 TCP的连接:
 七层模型之运输层
 客户端给服务器端发送一个包含同步报文标志SYN以及一个***i的TCP报文段,服务器收到后会给客户端发送一个包含SYN同步报文标志以及一个***j,并发送一个确认报文ACK,确认***为i+1的tcp报文段,当客户端收到来自服务器端的确认信息之后,会发送给服务器端一个包含ACK确认报文,***为j+1的tcp报文段,在这些过程完成之后,连接就建立了,此时connect()函数才返回。(从发送数据到接收到对方发来的确认报文的时间间隔称为RTT)
  TCP的传送:
  确认-应答机制:
    当客户端发送数据给服务器端时,tcp机制会将客户数据以及***,还有对方要确认的***以及本次确认的ACK报文***发送给服务器,服务器在收到该数据后,底层需要给客户端一个确认,发送以个***(为上一条中的”对方要确认的***”),以及一个确认ACK报文号,当用户层服务器端需要给客户端发送相应回复的数据时,底层就会将服务器端的数据发送给客户端,并且包含数据,***,以及对方要确认的***以及本次确认ACK报文号,当客户端收到数据后会再次给服务器端确认数据已经收到的一条确认信息,会给服务器发送一个ACK确认报文号。这样一个简单的从客户端应用层发送一条数据,服务器收到该数据后从用户层回复数据给客户端应用层的过程就完成了。这个过程称为”确认-应答”机制。
  TCP的释放:
  七层模型之运输层
  四次挥手机制:
  当客户端执行该函数时,客户端会给服务器发送一个包含通知连接关闭的FIN结束报文段标志,一个报文***i(这个i的值是在三次握手建立连接的第一条的***加1)以及一个确认关闭的标志ack,并且该ack的***为在三次握手建立连接时中的第三条中的客户端给服务器端发送的确认***的值。(关闭连接第一条);当服务器端收到通知之后,服务器会给客户端发送一个包含确认报文标志ack,以及确认***为i+1的tcp报文段,状态变为close wait(关闭连接第二条);之后服务器关闭连接,给客户端发送一个包含一个通知关闭的报文标志FIN,一个***j(j的值为关闭连接第一条中的确认***的值),以及一个确认关闭标志ack,并且确认***的值为关闭连接第二条中的确认***的tcp报文段(关闭连接第三条);当客户端收到该通知之后,发送给服务器端一个确认收到关闭通知的报文ACK,***为j+1(关闭连接第四条)。
  当服务器端要确认关闭时刚好服务器端也执行了close()函数时,那么第二条与第三条合并,变为“三次挥手”。
  TIME_WAIT的意义:
  TIME_WAIT状态系统大约会持续两分钟,其意义在于:
   a) 可靠地终止TCP的连接。
   b) 让迟来的报文能够有足够时间被识别,并且被丢弃。
   可靠地终止TCP的连接意思是说当最后确认服务器关闭连接的最后一个tcp报文段丢失,那么服务器会重新发送结束报文,所以客户端需要停留在某个阶段来处理这些重复收到的结束报文段,即向服务器端发送确认结束报文段。
   让迟来的报文能够有足够的时间被识别并丢弃是说如果没有TIME_WAIT状态,那么该端口会立即被其他连接所使用,重新建立一个与本连接具有相同的ip地址以及端口号的新连接,本连接一些迟来的数据报文便可能会被该新连接所接收,但这是不正确的,所以这就是对于迟到的报文为什么要被丢弃的原因。