网络:TCP

TCP特点

  • 点对点:一个发送方,一个接收方
  • 可靠的、按顺序的字节流:没有报文边界
  • 管道化(流水线):TCP拥塞控制和流量控制设置窗口大小(GBN和SR)
  • 发送和接收缓存
  • 全双工数据:在同一连接中数据双向流动
  • 面向连接:在数据交换之前,通过握手(交换控制报文)初始化发送方、接收方的状态变量
  • 有拥塞控制:发送方不会淹没接收方

TCP报文结构

  • 序号:报文段首字节在字节流的编号
  • 确认号:期望从另一方收到的下一个字节的序号,是个累计确认(ACK n表示确认n-1及以前的字节)
  • 序号和确认号都是以字节为单位的,用来实现可靠数据传输服务
  • 接收窗口:表示愿意接收的字节数量,用于流量控制
  • 可选与边长的选项字段:用于发送方和接收方协商最大报文长度MSS
  • 标志字段:
    • ACK:表示该报文段包含一个对已被成功接收报文段的确认
    • RST、SYN、FIN用于连接的建立和拆除
  • 接收方如何处理乱序的报文段是没有规定的

关于序号和确认号:

TCP把数据看成是一个无结构的、有序的字节流。所以TCP的序号和确认号都是建立在传送的字节流之上,而不是建立在传送的报文段的序号之上。

TCP的三次握手和四次挥手

三次握手

  1. 客户端TCP向服务器TCP发送一个建立连接的请求,将自己的初始序号(随机选择的,不一定是从0开始的)发送给对方;
    • 客户端的TCP会向服务器端发送一个特殊的TCP报文段。这个报文段不包含应用层数据。
    • 该报文段的首部中的一个标志位SYN被置为1,这个报文因此被称为SYN报文段
    • 客户端会随机选择一个初始序号放置于该SYN报文段的序号字段中
    • 该报文段会被封装在一个IP数据报中发送给服务器
  2. 服务端TCP向客户端TCP发送一个建立连接的确认,并把自己的初始序号发送给客户端TCP;
    • 服务器接收到IP数据报后,从数据包中提取 出SYN报文段,为该TCP连接分配TCP缓存和变量,并向该客户端TCP发送允许连接的报文段
    • 报文段包含内容:
      • SYN被置为1
      • 报文段首部的确认序号字段为接收到的序号+1
      • 服务端选择自己的的初始序号,并放到报文段首部的序号字段中
  3. 客户端向服务端发送对服务端的初始序号的确认
    • 客户端收到SYN+ACK报文段后,客户端也要给该连接分配缓存和变量。并向服务器发送对服务器允许连接的报文段进行确认的报文段(可以携带数据)。
    • 此时连接建立完成,SYN比特被置为0

客户和服务器主机可以开始互相发送包含数据的报文段了,以后每一个报文段中,SYN比特都将被置为0。

四次挥手

  1. 在客户端与服务器数据传输完毕之后,调用close,同时向服务器发送FIN结束报文段,等待服务器的响应;
  2. 当服务器收到了FIN结束报文段后,确认将关闭TCP连接,给客户端进行应答发送ACK,服务器进入CLOSE_WAIT状态。当客户端收到服务器的ACK响应时,进入FIN_WAIT_2状态;
  3. 此时,服务端可能还有数据向客户端发送,发送数据给客户端;
  4. 服务器提出反方向的关闭请求,调用close,向客户端发送FIN结束报文段;
  5. 客户端收到服务端发送的关闭请求后,开启定时器(2MLS),并向服务端发送关闭连接的确认,定时器结束时仍未收到服务端的报文,就认为连接已关闭,客户端关闭连接。

如果服务器没有发送FIN结束报文段,此连接的服务器长期保持在CLOSE_WAIT状态,这会有什么影响?

服务器长期保持在CLOSE_WAIT状态,也就是说分配的文件描述符并没有关闭并归还。那么大量的CLOSE_WAIT存在的话,就会导致一种资源的泄漏。可能到最后就没有可分配的文件描述符了,那么就会使一些客户端无法连接。

TIME_WAIT状态

在客户端最后一次发送ACK响应后,进入TIME_WAIT状态,而这个状态的时候客户端在做什么呢?

答案是等待。

在客户端最后发送ACK响应后,进入TIME_WAIT状态,这是为了防止最后发送的ACK响应丢包。在这里,TIME_WAIT状态会等待2MSL的时间。

这里的单位 MSL就是 Max Segment Life意思就是报文的最大生存时间,这里的生存时间指的是一个报文从发生到被接收到的整个过程,这个过程的时间就是MSL。

客户端最后一次发送ACK响应后,为什么要等待2MSL呢?

这是为了确保最后一条ACK消息的到达。因为客户端在发送最后一条ACK响应后进入TIME_WAIT状态,如果这条ACK报文丢失,那么服务器在等待一个MSL的时间过后发现没有收到ACK响应,那么它会重新发送一条FIN报文。这样一条ACK响应的时间加上重发的FIN的时间正好就是2MSL。如果客户端等待2MSL后没有收到FIN报文,那么意味着服务器收到了客户端发送的ACK报文,这样就断开连接。

TCP怎样保证传输可靠性

TCP协议传输的特点就是面向字节流、传输可靠、面向连接。

TCP协议保证数据传输可靠性的方式有:校验和、序列号、确认应答、超时重传、流量控制、拥塞控制

校验和

计算方式:在数据传输的过程中,将发送的数据段都当做一个16位的整数,将这些整数加起来。并且前面的进位补在后面,最后取反,得到校验和。

发送方:在发送数据之前计算校验和,并进行校验和的填充。

接收方:收到数据后,对数据以同样的方式进行计算,求出校验和,与发送的进行比对。

如果接收方与发送方的校验和不一致,那么数据一定传输有误。但是,接收方与发送方的校验和一致,数据不一定传输成功。

确认应答与序列号

序列号:TCP传输时将每个字节的数据都进行了编号,就是序列号

确认应答:TCP传输的过程中,每次接收方收到数据后,都会对传输方进行确认应答,也就是发送ACK报文。这个ACK报文当中带有对应的确认序列号,告诉发送方,接收到了哪些数据,下一次的数据从哪里发。

序列号的作用不仅仅是应答的作用,有了序列号后能够将接收到的数据根据序列号排序,并且去掉重复序列号的数据。

超时重传

在进行TCP传输时,由于确认应答与序列号机制,发送方发送一部分数据后,都会等待接收方发送的ACK报文,并解析ACK报文判断数据是否发送成功。如果发送方发送完数据后,迟迟没有收到接收方的ACK报文,那么发送方会对刚才发送的数据进行重新发送。

发送方没有收到响应的ACK报文的原因可能有两点:

1、数据在传输过程中由于网络原因等直接全体丢包,接收方根本没有接收到;

2.、接收方收到了响应的数据,但是发送的ACK报文响应却由于网络原因丢包了;

超时重传时,如果接收方之前没收到数据,那么收到重发数据后,进行ACK应答;如果接收方之前已经收到数据,收到重发的数据后发现数据已经存在,会直接丢弃,仍旧发送ACK应答。

流量控制

TCP连接收到正确、按序的字节后就将数据放入接收缓存。相关联的应用进程会从该缓存中读取数据,但不必是数据刚一到达就立即读取。如果接收方应用程序读取数据相对缓慢,而发送方发送得太多太快,发送的数据很容易使接收方的缓存溢出。此时如果发送端仍旧发送数据,那么接下来发送的数据都会丢包,继而导致丢包的一系列连锁反应,比如超时重传。

TCP根据接收端对数据的处理能力,决定发送端的发送速度,这个机制就是流量控制。

在TCP协议的报头信息当中,有一个16位字段的窗口大小。这个窗口大小实际上是接收端空闲缓冲区的大小。

接收端会在确认应答发送ACK报文时,将自己的即时窗口大小填入,并跟随ACK报文一起发送过去。而发送方根据ACK报文里的窗口大小的值的改变进而改变自己的发送速度。如果接收到窗口大小的值为0,那么发送方将停止发送数据。并定期的向接收端发送窗口探测数据段,让接收端把窗口大小告诉发送端。

拥塞控制:慢启动、拥塞避免、快速恢复

TCP传输的过程中,发送端开始发送数据的时候,如果刚开始就发送大量的数据,那么就可能造成一些问题。网络可能在开始的时候就很拥堵,如果网络中再扔出大量数据,那么这个拥堵就会加剧。拥堵的加剧就会产生大量的丢包,就需要大量的超时重传,严重影响传输。TCP通过慢启动、拥塞避免、快速恢复机制来进行拥塞控制。

  • 慢启动

    当一条TCP连接开始时,拥塞窗口的值通常初始置为一个MSS的较小值,由于对TCP发送方而言,可用带宽可能比当前发送速率大得多,TCP发送方希望迅速找到可用带宽的数量。因此,在慢启动状态,拥塞窗口的值以1个MSS开始并且每当传输的报文段首次被确认就增加1个MSS,并发送出两个最大长度的报文段。这两个报文段被确认,则发送方对每个确认报文段将拥塞窗口增加一个MSS,使得拥塞窗口变为4个MSS,并这样下去。这一过程每过一个RTT,发送速率就翻番。因此,TCP发送速率起始慢,但在慢启动阶段以指数增长。

  • 拥塞避免

    如果发生超时,表示当前发生拥塞。发送方将拥塞窗口设置为1并重新开始慢启动,并将慢启动阈值更新为拥塞发生时拥塞窗口大小的一半。当拥塞窗口达到慢启动阈值时,结束慢启动,进入到拥塞避免阶段。

    拥塞避免阶段,开始线性增加拥塞窗口的大小;当检测到3个冗余ACK时,TCP将拥塞窗口和拥塞窗口阈值都更新为当前的拥塞窗口大小的一半,并执行快速重传,然后进入快速恢复阶段。

    快速重传:在收到3个冗余ACK的时候(网络发生轻微拥塞),在超时定时器超时前就重传丢失的报文。

  • 快速恢复

    在快速恢复状态,对收到的每个冗余的ACK,拥塞窗口的值增加一个MSS。最终,当丢失报文段的一个ACK到达时,TCP在降低拥塞窗口大小后进入拥塞避免阶段。

多路复用和解复用

概念和过程

多路复用

  • 在发送方主机多路复用
  • 从不同套接字接收来自多个进程的数据块,并为每个数据块封装上根据套接字对应的IP地址和端口号等信息封装的头部,从而生成报文段,然后将报文段传递到网络层。

多路解复用:

  • 在接收端主机多路解复用
  • 根据报文段的头部信息中的IP地址和端口号将接收的报文段发给正确的套接字(和对应的应用进程)

解复用的作用:TCP或UDP实体采用哪些信息,将报文段的数据部分交给正确的socket,从而交给正确的进程。

过程:

  1. 主机收到IP数据报
    • 每个数据报都有源IP地址和目标IP地址
    • 每个数据报承载一个传输层报文
    • 每个报文段有一个源端口号和目标端口号
  2. 主机联合使用IP地址和端口号将报文段发送给合适的套接字

TCP的多路复用和多路分解

TCP的socket是由一个四元组来表示的,包含源IP地址、源端口号、目的IP地址、目的端口号。每个socket是跟对应的应用进程的pid捆绑的。

在发送端:

  • 应用层向TCP层交的有数据本身、socket

  • TCP将socket中的源端口和目标端口号封装到报文段的头部,并将报文段、源IP和目标IP往下交给IP层;

  • IP层拿到上层交过来的TCP报文段后,将socket的源IP和目标IP封装到IP分组的头部,发送出去。

在接收端:

  • 当数据到达网络层时,网络层去掉IP分组的头部,并将TCP报文、源IP、目标IP(发送方和接收方的IP)交给TCP应用;
  • TCP去掉报文段的头部,并根据源IP、目标IP、源端口号、目标端口号定向到相应的套接字socket。

UDP的多路复用和解复用

UDP的socket是和源端的IP和端口号绑定的

在发送数据的时候(复用):

应用层向UDP层交的数据有数据本身、socket和目标主机的IP和端口号生成的socket的地址&cad

UDP拿到之后封装报文段时,用上层交过来的的源Port和从&cad中拿到对应的目标端口号封装成报文段的头部,然后将报文段往下交给IP层;

IP层拿到报文段后,将上层交过来的源端IP和从&cad中拿到目标IP封装到IP分组的头部,然后将IP分组发送出去。

在接收端(解复用):

当数据到达网络层时,网络层去掉IP分组的头部,并将TCP报文、源IP、目标IP(发送方和接收方的IP)交给TCP应用;

TCP去掉报文段的头部,并根据源IP、目标IP、源端口号、目标端口号定向到相应的套接字socket

滑动窗口协议

滑动窗口协议包括停等协议和流水线协议。

停等协议(SW——stop and wait):发送方发送一个分组,都要停下来等待接收方的确认才能继续发送下一个分组

流水线协议:允许发送方在未得到对方确认的情况下一次发送多个分组

  • 必须增加序号的范围:用多个bit表示分组的序号
  • 在发送方/接收方要有缓冲区:
    • 发送方缓冲:未得到确认,可能需要重传;
    • 接收方缓存:上层用户取得数据的速率 != 接收到的数据速率——接收到的数据可能乱序,需要排序交付

两种通用流水线协议:回退N步(GBN)和选择重传(SR)

发送缓冲区

  • 形式:内存中的一个区域,落入缓冲区的分组可以发送
  • 功能:用于存放已发送,但是没有得到确认的分组
  • 必要性:需要重发时可用

发送缓冲区的大小:一次最多可以发送多少个未经确认的分组

  • 停等协议:只能发送一个
  • 流水线协议: > 1,取合理的值,不能很大,链路利用率不能超过100%

发送缓冲区中的分组:

  • 未发送:落入发送缓冲区的分组,可以连续发送出去
  • 已经发送出去的,等待对方确认的分组:发送缓冲区的分组只有得到确认才能删除

不同协议的窗口大小

发送窗口:是发送缓冲区内容的一个范围,是由已发送但是未经确认的分组的序号构成的空间

发送窗口的最大值 ≤ 发送缓冲区的值。

各协议窗口大小

  • SW协议:发送窗口 = 1,接收窗口 = 1
  • GBN协议:发送窗口 > 1,接收窗口 = 1
  • SR协议:发送窗口 > 1,接收窗口 > 1

接收窗口RW = 1:只能顺序接收。每收到一个分组,都发送自己等待的那个分组的确认;ACK(x)表示序号x和x之前的分组都已经接收到,是一种累计确认。

接收窗口RW > 1,每收到一个分组Package x,都发送该分组的确认ACK(x),是一个独立确认。如果前面有分组一直未收到,会通过超时重传机制来进行发送。

GBN协议:只有一个超时定时器,当最前面的那个分组一直未接收到确认时,超时重传机制会把所有已发送但未确认的分组重新发送一遍;对乱序的分组丢弃,不做缓存;

SR协议:

  • 接收方对每个正确接收的分组,分别发送ACK(x);
  • 由于接收窗口 > 1,所以可以缓存乱序的分组,最终将分组按顺序交付给上层;
  • 发送方只对那些没有收到ACK的分组进行重发——选择性重发(发送方为每个未确认的分组设定一个定时器)
  • 发送窗口的最大值(发送缓冲区)限制未确认分组的个数