计算机网络笔记整理(四)

前言

       运输层是整个网络体系结构中的关键层次。TCP/IP体系中运输层最重要的两个协议:UDP和TCP。运输层是在主机的协议栈中的,TCP是保证可靠的交付,UDP是尽最大努力的交付。重点是TCP的各种机制是如何保证可靠交付,在面向连接的可靠服务、流量控制、拥塞控制等方面作出了何种的努力,以及TCP连接的三次握手和断开连接的四次挥手以及为什么这样设计。本节篇幅很长,多图,内容很关键。

知识点

进程之间的通信

       从通信和信息处理的角度看,运输层向它上面的应用层提供通信服务,它是面向通信部分的最高层,也是用户功能的最低层。当网络的边缘部分的两个主机利用网络的核心部分的功能进行端到端的通信时,只有主机的协议栈才有运输层,而网络核心部分中的路由器在转发分组的时候都只用到了下三层的功能。

       从上图可知:从IP层来说,通信的是主机,但是两个主机之间通信的说法还不够清楚,这是因为,真正进行通信的实体是两个主机上的进程,从运输层来看并不是主机而是主机上的进程。

       运输层提供应用进程之间的逻辑通信。意思是:运输层之间的通信好像是沿着水平方向传送数据,但实际并没有物理连接。数据在多个层次之间传送。(网络层是主机之间的逻辑通信),如之前所讲运输层还进行差错检测等,运输层向高层屏蔽了下面网络核心的细节,它使应用进程看见的好像是两个运输实体之间一条端到端的逻辑通信,当然运输层协议不同对上层的表现也很大不同。

TCP和UDP

概述和相关应用

       运输层的两个主要协议:用户数据报协议UDP和传输控制协议TCP。UDP面向无连接,不提供可靠交付,但是却是一种最有效的工作方式。TCP提供面向连接的,可靠的服务。TCP不提供多播服务,依赖额外的开销进行,确认、流量控制、计时器、连接管理等,协议数据单元的首部变大,也占用了很多处理机资源。下面给出两种协议在应用层的相关应用。

              

       两者之间的区别如下:

              

端口的由来

       运输层和应用层采用了复用和分用,应用层所有的应用进程都可以利用运输层传到IP层,运输层从IP层收到数据后在指定某个进程交付通信。现在重点是给每个应用进程赋予一个非常明确的标志。然而不同的操作系统有不同的进程标识符(一个不大的整数),所以TCP/IP体系对进程统一标志。即使是这样,还存在问题,比如要和因特网上的某个邮件服务器通信,我在不知道对方的进程没法完成通信,显然是不科学的,解决方法是:在运输层使用协议端口号,虽然说通信终点是应用进程,但是我们只用把数据送到指定端口,剩下来的工作交给TCP去完成。常见的端口号如下:

UDP

特点:

1.无连接,减小了开销和时延。

2.最大努力交付,不保证可靠交付,不需要维持复杂的状态连接表。

3.面向报文,对于应用层的报文,只添加首部,保留边界,一次性交付,所以应用程序要选择合适大小的报文,太长或太短都会降低IP层效率,长了会分片,短了首部相对就太长。

4.没有拥塞控制,支持一对一,一对多,多对多的交互通信,首部开销小。

              

首部格式

       UDP首部较为简单,包含四个部分,其中伪首部是计算检验和时临时添加,并不向上或向下传递,如下图:

TCP

特点

1.面向连接。先建立连接在通信,最后释放连接。就像打电话一样。

2.连接只能是一对一点对点。

3.提供可靠交付,无差错、不丢失、不重复、按序到达。

4.全双工通信,双方任何时候都能发送,两端都设有发送和接收缓存。

5.面向字节流。TCP并不知道所传数据的含义,统一当成无结构的字节流,存在发送方发送10个数据块,接收方只用了4个数据块就把收到的字节流交付给应用层。当然接收方的应用程序必须有能力识别收到的字节流并还原成应用层数据。

可靠传输的工作原理

停止等待协议–应用:ARQ自动重传请求

       每发送完一个分组就停止发送,等待对方确认,收到确认在发送下一个分组。

               

       如果出现差错,就要超时重传,为了实现这一功能,需要做以下工作:

       1.设计超时计时器,且超时时间比平均往返时间更长。(超时时间设定是个复杂问题)

       2.必须保留已发送分组的副本。

       3.对发送的分组编号,才知道哪个没发送成功。

       4.确认丢失和确认迟到。也许超时之后,接收方还是收到了,这时候就会丢弃重复的分组,进行确认,分为确认丢失和确认迟到,所以说,发送方总是会收到确认,如果总是收不到说明通信线路太差不能通信。

TCP首部格式(重点)

       虽然TCP是面向字节流的,但是TCP传送的数据单元却是报文段。20+4N的格式,20是固定的,根据需要以4N字节增加。

       

  1. 源端口和目的端口,各占2个字节,分别写入源端口号和目的端口号。

  2. 序号 占4个字节,范围时0到2^32-1,采用mod 2^32运算。

  3. 确认号 期望收到对方下一个报文段的第一个数据字节的序号。

  4. 数据偏移 占4位,指定TCP报文段的首部长度,4位二进制最大时十进制15,以4歌字节为计算单位,所以,首部最大长度时60,即选项长度最大60。

  5. 保留为今后使用,预留字段6位,目前为0。

  6. 紧急URG URG为1则高优先级传送,而不需要排队,和紧急指针配合使用。

  7. 确认ACK 仅等于1才有效,确认连接后所有传送的报文段都必须把ACK置为1。
  8. 推送 PSH 希望立即收到对方响应,这时要把PSH置为1,立即创建报文传出去,接收方不在进入缓存而直接进入应用进程。但很少使用。
  9. 复位RST 当RST=1时,表明TCP连接出现严重差错需要立即释放。
  10. 同步SYN 当SYN=1而ACK=0时表明这是一个连接请求,SYN置为1表示这是一个连接请求或者连接接受报文。
  11. 终止FIN 用来释放一个连接。置为1时释放连接。
  12. 窗口 占2个字节,所以窗口值是0到2^16-1之间的整数,窗口值作为接收方让发送方设置其发送窗口的依据。表明现在允许对方发送的数据量,动态变化。
  13. 检验和 2个字节,检验的范围包括首部和数据这两部分。同样和UDP一样要加上12个字节的伪首部,伪首部的协议号17修改为6(TCP的协议号),长度字段,如果使用ipv6相应地方也要改变。
  14. 紧急指针 2个字节,仅在URG=1才有意义,指定本报文段中的紧急数据所在位置。
  15. 选项 长度可变,最多40,4个为基本单位。选项中有窗口扩大、时间戳、选择确认等。

TCP可靠传输的实现

综述

  1. 确认和重传:接收方收到报文就会确认,发送方发送一段时间后没有收到确认就重传。

  2. 数据校验

  3. 数据合理分片和排序:
    UDP:IP数据报大于1500字节,大于MTU.这个时候发送方IP层就需要分片(fragmentation).把数据报分成若干片,使每一片都小于MTU.而接收方IP层则需要进行数据报的重组.这样就会多做许多事情,而更严重的是,由于UDP的特性,当某一片数据传送中丢失时,接收方便无法重组数据报.将导致丢弃整个UDP数据报.
    tcp会按MTU合理分片,接收方会缓存未按序到达的数据,重新排序后再交给应用层。

  4. 流量控制:当接收方来不及处理发送方的数据,能提示发送方降低发送的速率,防止包丢失。

  5. 拥塞控制:当网络拥塞时,减少数据的发送。

还可以参考这个博客:如何讲清楚TCP的可靠性传输

以字节为单位的滑动窗口

为什么使用窗口

       因为发送端希望在收到确认前,继续发送其它报文段。比如说在收到0号报文的确认前还发出了1-3号的报文,这样提高了信道的利用率。但可以想想,0-4发出去后可能要重传,所以需要一个缓冲区维护这些报文,所以就有了窗口。

              

窗口怎么实现
接收窗口

       接收窗口”大小取决于应用(比如说tomcat:8080端口的监听进程)、系统、硬件的限制。图中,接收窗口是31~50,大小为20。

  1. 在接收窗口中,黑色的表示已收到的数据,白色的表示未收到的数据。
  2. 当收到窗口左边的数据,如27,则丢弃,因为这部分已经交付给主机;
  3. 当收到窗口左边的数据,如52,则丢弃,因为还没轮到它;
  4. 当收到已收到的窗口中的数据,如32,丢弃;
  5. 当收到未收到的窗口中的数据,如35,缓存在窗口中。

tips:按序到达的、但尚未被接收应用程序读取的数据和未按序到达的数据

  
  

发送窗口

发送窗口的大小swnd=min(rwnd,cwnd)。rwnd是接收窗口,cwnd用于拥塞控制,暂时可以理解为swnd= rwnd =20。图中分为四个区段,其中P1到P3是发送窗口。发送窗口以字节为单位。为了方便画图,图中展示得像以报文为单位一样。但这不影响理解。

tips:发送应用程序传送给发送方TCP准备发送的数据和TCP已经发送出但尚未收到确认的数据

总结

强调以下三点:

  1. 虽然A的发送窗口是根据B接受窗口设置的,但在同一时刻,A和B的窗口大小并不一定一样,这是因为传送需要一个时延而且是不确定的。发送方A还可能根据当时的网络拥塞减小窗口数值。
  2. 对于不按序到达的数据该如何处理,TCP标准并无明确规定,如果接收方一律丢弃,那么管理相对简单,但是对网络资源利用率下降,所以通常是对不按序到达的数据先临时存放在接收窗口中,等到字节流中所缺少的字节收到后再交付给上层进程。
  3. TCP要求接收方必须有 累积确认 的功能,这样可以减少传输开销。因为只确认收到最后一个分组代表之前的全都正确传输。可以在合适的时候发送确认,不会导致不必要的重传,TCP规定确认推迟时间不超过0.5秒。

超时重传时间的选择

       TCP采用了一种自适应的算法,它记录RTT,加权平均的RTTs,超时重传时间:

                                                 RTO=RTTs+4*RTTD

       RTTD第一次测量时为RDDs的一半,在使用下式计算甲醛平均的RTTD:

                             RTTD=(1-x)*(旧的加权平均RTTD)+x|RTTs-新的RTT|

      其中x建议为0.25.

流量控制

      有一种情况可能导致死锁。B向A发送零窗口报文段,然后就有缓存空间了,又向A发送一定长度的报文,但是A收到零窗口报文之后一直等待非零窗口的通知,B传的数据就丢失了,A和B一直都在等待,出现死锁。

      解决:TCP为每个连接设置一个持续计时器。只要连接一方接收到零窗口的通知,就启动,若在设置时间内到期,就发送一个零窗口一个字节的探测报文段,对方给出现在的窗口值。

      合适时间确认的选择:接收方等待一段时间或者等到缓存已有一半空闲空间。

拥塞控制

     网络资源(链路容量即带宽、交换节点种缓存和处理机)呈现供应不足,整个网络性能就会变坏。吞吐量随着负荷增加而下降。这就是拥塞。

    拥塞控制和流量控制息息相关,但也有一些差别,拥塞控制是防止过多的数据注入到网络导致路由器或者链路的过载,是全局性的把控,流量控制往往只点到点通信量的控制,是端到端的问题。

    几种拥塞控制方法:慢开始、拥塞避免、快重传、快恢复等还有相关改进。

TCP连接建立和释放

建立连接

   所谓三次握手(Three-Way Handshake)即建立TCP连接,就是指建立一个TCP连接时,需要客户端和服务端总共发送3个包以确认连接的建立。在socket编程中,这一过程由客户端执行connect来触发,整个流程如下图所示:

                

  1. 第一次握手:Client将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给Server,Client进入SYN_SENT状态,等待Server确认。
  1. 第二次握手:Server收到数据包后由标志位SYN=1知道Client请求建立连接,Server将标志位SYN和ACK都置为1,ack=J+1,随机产生一个值seq=K,并将该数据包发送给Client以确认连接请求,Server进入SYN_RCVD状态。
  1. 第三次握手:Client收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给Server,Server检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,Client和Server进入ESTABLISHED状态,完成三次握手,随后Client与Server之间可以开始传输数据了。

释放连接

   所谓四次挥手(Four-Way Wavehand)即终止TCP连接,就是指断开一个TCP连接时,需要客户端和服务端总共发送4个包以确认连接的断开。在socket编程中,这一过程由客户端或服务端任一方执行close来触发,整个流程如下图所示:

                

  1. 第一次挥手:Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。
  1. 第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server进入CLOSE_WAIT状态。
  1. 第三次挥手:Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态。
  1. 第四次挥手:Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,Server进入CLOSED状态,完成四次挥手。

   上面是一方主动关闭,另一方被动关闭的情况,实际中还会出现同时发起主动关闭的情况,具体流程如下图:

                

tips:为什么建立连接是三次握手,而关闭连接却是四次挥手呢?

     原因是因为tcp是全双工模式,接收到FIN时意味将没有数据再发来,但是还是可以继续发送数据。服务端在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。而关闭连接时,当收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方也未必全部数据都发送给对方了,所以己方可以立即close,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送。

为什么需要“三次握手”

    在谢希仁著《计算机网络》第四版中讲“三次握手”的目的是“为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误”。在另一部经典的《计算机网络》一书中讲“三次握手”的目的是为了解决“网络中存在延迟的重复分组”的问题。这两种不用的表述其实阐明的是同一个问题。

    谢希仁版《计算机网络》中的例子是这样的,“已失效的连接请求报文段”的产生在这样一种情况下:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。”。主要目的防止server端一直等待,浪费资源。

参考:1.什么是三次握手和四次挥手。2.为什么要三次握手和四次挥手

socket通信

       Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

       注意:其实socket也没有层的概念,它只是一个facade设计模式的应用,让编程变的更简单。是一个软件抽象层。在网络编程中,我们大量用的都是通过socket实现的。

              

说明

       文中出现的图片,文字描述有些来自互联网,但是出处无法考究,如果侵犯您的相关权益,请联系我,核实后我会马上加上转载说明。谢谢!