[IT]图解TCP-IP协议

本文通过两个图来梳理TCP-IP协议相关知识。TCP通信过程包括三个步骤:建立TCP连接通道传输数据断开TCP连接通道。如图1所示,给出了TCP通信过程的示意图。

[IT]图解TCP-IP协议_第1张图片

                                      图1 TCP 三次握手四次挥手

图1主要包括三部分:建立连接、传输数据、断开连接

  • 建立TCP连接很简单,通过三次握手便可建立连接。
  • 建立好连接后,开始传输数据。TCP数据传输牵涉到的概念很多:超时重传、快速重传、流量控制、拥塞控制等等。
  • 断开连接的过程也很简单,通过四次握手完成断开连接的过程。

1.三次握手建立连接

  • 第一次握手:客户端发送SYN包(seq=x)到服务器,并进入SYN_SEND状态,等待服务器确认;
  • 第二次握手:服务器收到SYN包,必须确认客户的SYN(ACK=x+1),同时自己也发送一个SYN包(seq=y),即SYN+ACK包,此时服务器进入SYN_RECV状态;
  • 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ACK=y+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。

    握手过程中传送的包里不包含数据,三次握手完毕后,客户端与服务器才正式开始传送数据。理想状态下,TCP连接一旦建立,在通信双方中的任何一方主动关闭连接之前,TCP 连接都将被一直保持下去。

2.传输数据过程

  • 2.1.超时重传

    超时重传机制用来保证TCP传输的可靠性。TCP通过肯定的确认应答(ACK)实现可靠的数据传输。当发送端将数据发出之后会等待对端的确认应答。如果有确认应答,说明数据已经成功到达对端,反之,则数据丢失的可能性很大。在一定时间内没有等到确认应答,发送端就可以认为数据已经丢失,并进行重发。由此,即使产生了丢包,仍然能够保证数据能够到达对端。
    每次发送数据包时,发送的数据报都有seq号,接收端收到数据后,会回复ack进行确认,表示某一seq号数据已经收到。发送方在发送了某个seq包后,等待一段时间,如果没有收到对应的ack回复,就会认为报文丢失,会重传这个数据包。

    [IT]图解TCP-IP协议_第2张图片

    未收到确认应答并不意味数据一定丢失。也有可能是数据对方已经收到,只是返回的确认应答在途中丢失。这种情况也会导致发送端因没有收到确认应答,而认为数据没有到达目的地,从而进行重传。

    [IT]图解TCP-IP协议_第3张图片

  • 2.2 超时重传时间确定

    超时重传的时间是如何确定的呢?最理想的是,找到一个最小时间,它能保证“确认应答一定能在这个时间内返回”。然而这个时间长短随着数据包途径的网络环境的不同而有所变化。因此,它在每次法宝时都会计算往返时间以及偏差。将这个往返时间和偏差相加为重发超时的时间。如下图所示,不同的网络环境的不同往返时间可能会产生大幅度的摇摆,之所以发生这种情况是因为数据包的分段是经过不同路线到达的。

    [IT]图解TCP-IP协议_第4张图片

  • 2.3.快速重传

    接受数据一方发现有数据包丢掉了。就会发送ack报文告诉发送端重传丢失的报文。如果发送端连续收到标号相同的ack包,则会触发客户端的快速重传。比较超时重传和快速重传,可以发现超时重传是发送端在傻等超时,然后触发重传;而快速重传则是接收端主动告诉发送端数据没收到,然后触发发送端重传。

  • 2.4.滑动窗流量控制

    这里主要说TCP滑动窗流量控制。TCP头里有一个字段叫Window,又叫Advertised-Window,这个字段是接收端告诉发送端自己还有多少缓冲区可以接收数据。于是发送端就可以根据这个接收端的处理能力来发送数据,而不会导致接收端处理不过来。 滑动窗可以是提高TCP传输效率的一种机制。

  • 2.5.拥塞控制

    滑动窗用来做流量控制。流量控制只关注发送端和接受端自身的状况,而没有考虑整个网络的通信情况。拥塞控制,则是基于整个网络来考虑的。考虑一下这样的场景:某一时刻网络上的延时突然增加,那么,TCP对这个事做出的应对只有重传数据,但是,重传会导致网络的负担更重,于是会导致更大的延迟以及更多的丢包,于是,这个情况就会进入恶性循环被不断地放大。试想一下,如果一个网络内有成千上万的TCP连接都这么行事,那么马上就会形成“网络风暴”,TCP这个协议就会拖垮整个网络。为此,TCP引入了拥塞控制策略。拥塞策略算法主要包括:慢启动,拥塞避免,拥塞发生,快速恢复

    首先,为了在发送端调节所要发送数据的量,定义了一个叫做“拥塞窗口”的概念。于是再慢启动的时候,将这个拥塞窗口的大小设置为1个数据段发送数据,之后每收到一次确认应答(ACK),拥塞窗口的值就加1。在发送数据包时,将拥塞窗口的大小与接收端主机通知的窗口大小做比较,然后按照当中较小的那个值,发送比其还要小的数据量。

    如果重发采用超时重传机制,那么拥塞窗口的初始值可以设置为1以后再进行慢启动修正。
    不过,随着包的每次往返,拥塞窗口也会以1,2,4等指数函数的增长,拥塞状况激增甚至导致网络拥塞的发生。为了防止这些,引入了慢启动阈值的概念。只要拥塞窗口的值超过阈值,在每收到一次确认应答时,只允许一下面这种比例放大拥塞窗口:

    1个数据段的字节数/拥塞窗口(字节)* 1个数据段字节数
    

    [IT]图解TCP-IP协议_第5张图片

3.四次握手断开连接

  • 第一次挥手:主动关闭方发送一个FIN,用来关闭主动方到被动关闭方的数据传送,也就是主动关闭方告诉被动关闭方:我已经不会再给你发数据了(当然,在fin包之前发送出去的数据,如果没有收到对应的ack确认报文,主动关闭方依然会重发这些数据),但此时主动关闭方还可以接受数据。
  • 第二次挥手:被动关闭方收到FIN包后,发送一个ACK给对方,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号)。
  • 第三次挥手:被动关闭方发送一个FIN,用来关闭被动关闭方到主动关闭方的数据传送,也就是告诉主动关闭方,我的数据也发送完了,不会再给你发数据了。
  • 第四次挥手:主动关闭方收到FIN后,发送一个ACK给被动关闭方,确认序号为收到序号+1,至此,完成四次挥手。

4.状态转移

[IT]图解TCP-IP协议_第6张图片

为了更好的理解这个图,你可以首先沿着客户端的路径(粗实线),然后沿着服务器端路径(粗虚线)来查看。

当客户机器上的一个应用程序发出CONNECT请求的时候,本地的TCP实体来创建一条连接记录,并将他标记为SYN_SENT状态,然后发送一个SYN数据段。注意,在一台机器上可能同时有许多个连接处于打开(或者被动打开)的状态,它们可能代表了多个应用程序,所以,状态是针对每一个链接的,并且每个连接的状态被记录在相应的连接记录中。当SYN+ACK到达时,TCP发出三步握手过程的最后一个ACK数据段,并且切换到ESTABLISHED状态。现在可以发送和接受数据了。

当一个应用结束的时候,它执行CLOSE原语,从而使本地的TCP实体发送一个FIN数据段,并等待对应的ACK(虚线框标记了主动的关闭过程)。当ACK到达的时候,发生一次状态迁移,切换到FIN_WAIT_2 ,而且连接的一个方向现在被关闭。当另一方也关闭的时候,一个FIN数据段会到来,然后它被确认。现在双方都已经关闭了,但是TCP要等待一段最大分组生存期的时间,以确保所有的分组都已经消失了,以防万一万一发生确认丢失的情形。

现在我们从服务器角度来看一下连接管理。服务器执行LISTEN,并等待有人连接上来。当有一个SYN数据段进来的时候,它被确认,并且服务器进入SYN_RECD状态。当服务器的SYN本身被确认的时候,三步握手过程结束,服务器进入到ESTABLISHED状态。从现在开始可以传输数据了。

建立连接时服务器端和客户端产生的状态转移说明:

  • CLOSED:起始点,在超时或者连接关闭时候进入此状态。

  • LISTEN:服务端在等待连接过来时候的状态,服务端为此要调用socket,bind,listen函数,就能进入此状态。此称为应用程序被动打开(等待客户端来连接)。

  • SYN_SENT:客户端发起连接,发送SYN给服务器端。如果服务器端不能连接,则直接进入CLOSED状态。

  • SYN_RCVD:跟3对应,服务器端接受客户端的SYN请求,服务器端由LISTEN状态进入SYN_RCVD状态。同时服务器端要回应一个ACK,同时发送一个SYN给客户端;另外一种情况,客户端在发起SYN的同时接收到服务器端得SYN请求,客户端就会由SYN_SENT到SYN_RCVD状态。

  • ESTABLISHED:服务器端和客户端在完成3次握手进入状态,说明已经可以开始传输数据了。

连接关闭时候的状态转移说明,关闭需要进行4次双方的交互,还包括要处理一些善后工作(TIME_WAIT状态),注意,这里主动关闭的一方或被动关闭的一方不是指特指服务器端或者客户端,是相对于谁先发起关闭请求来说的:

  • FIN_WAIT_1:主动关闭的一方,由状态5进入此状态。具体的动作是发送FIN给对方。

  • FIN_WAIT_2:主动关闭的一方,接收到对方的FIN-ACK(即fin包的回应包),进入此状态。

  • CLOSE_WAIT:接收到FIN以后,被动关闭的一方进入此状态。具体动作是接收到FIN,同时发送ACK。(之所以叫close_wait可以理解为被动关闭方此时正在等待上层应用发出关闭连接指令)

  • LAST_ACK:被动关闭的一方,发起关闭请求,由状态8进入此状态。具体动作是发送FIN给对方,同时在接收到ACK时进入CLOSED状态。

  • CLOSING:两边同时发起关闭请求时,会由FIN_WAIT_1进入此状态。具体动作是接收到FIN请求,同时响应一个ACK。

  • TIME_WAIT:最纠结的状态来了。从状态图上可以看出,有3个状态可以转化成它,我们一一来分析:

      a.由FIN_WAIT_2进入此状态:在双方不同时发起FIN的情况下,主动关闭的一方在完成自身发起的关闭请求后,接收到被动关闭一方的FIN后进入的状态。
    
      b.由CLOSING状态进入:双方同时发起关闭,都做了发起FIN的请求,同时接收到了FIN并做了ACK的情况下,由CLOSING状态进入。
    
      c.由FIN_WAIT_1状态进入:同时接受到FIN(对方发起),ACK(本身发起的FIN回应),与b的区别在于本身发起的FIN回应的ACK先于对方的FIN请求到达,而b是FIN先到达。这种情况概率最小。
    

关闭的4次连接最难理解的状态是TIME_WAIT,存在TIME_WAIT的2个理由:

1.可靠地实现TCP全双工连接的终止。

2.允许老的重复分节在网络中消逝。

5.慢热启动算法 – Slow Start

首先,我们来看一下TCP的慢热启动。慢启动的意思是,刚刚加入网络的连接,一点一点地提速,不要一上来就像那些特权车一样霸道地把路占满。新同学上高速还是要慢一点,不要把已经在高速上的秩序给搞乱了。

慢启动的算法如下(cwnd全称Congestion Window):

  • 连接建好的开始先初始化cwnd = 1,表明可以传一个MSS大小的数据。

  • 每当收到一个ACK,cwnd++; 呈线性上升

  • 每当过了一个RTT,cwnd = cwnd*2; 呈指数让升

  • 还有一个ssthresh(slow start threshold),是一个上限,当cwnd >=ssthresh时,就会进入“拥塞避免算法”(后面会说这个算法)

所以,我们可以看到,如果网速很快的话,ACK也会返回得快,RTT也会短,那么,这个慢启动就一点也不慢。

你可能感兴趣的:(tcp,tcp连接,TCP-IP)