TCP/IP协议详解(二):建立和关闭连接

作者: remcarpediem
联系方式:segmentfaultcsdn简书

本文转载请注明作者、文章来源,链接,版权归作者所有。

 看了酷壳网站上的《TCP 的那些事儿》系列文章,有一点很受启发:锻炼一下自己是否使用较少的篇幅将TCP协议讲解清楚。一般的同学写博文,可能像摊大饼一样,篇幅较多并且罗嗦。我以前写文章时也是这个习惯,所以希望在以后的博文写作过程中,尽量使用比较短的篇幅来讲完想要讲的内容。
 为了节约你的时间,本片文章主要讲解一下内容:

  • TCP连接的建立和关闭
  • TCP报文的ack number和 seq number的含义

TCP状态机

我们都说TCP是面向连接的传输协议,但是网络传输都是没有连接的,包括TCP也是一样。TCP所谓的“连接”,其实就是通讯双方维护的一个“连接状态”,让它看上去像是有连接一样。所以,TCP的状态转移是非常重要的。

 TCP的不同状态和状态转移构成了所谓的TCP状态机,如下图所示。我们先在介绍一下其中的几个术语和状态
TCP状态机

  • 主动打开(active open)是指客户端发送第一个SYN报文,它主动发起建立TCP连接的请求。
  • 被动打开(passive open)是指服务端接受第一个SYN报文并且发回一个SYN报文,它响应建立TCP连接的请求。
  • SYN-SENT是指客户端发送第一个SYN报文并等待接受服务端SYN+ACK报文时的状态,一旦接受到SYN+ACK报文,客户端状态就变为建立连接(ESTABLISHED)了。
  • SYN-RECEIVED是指服务端接受到第一个SYN报文并发回SYN+ACK报文等待客户端ACK报文时的状态,一旦接受到客户端发送的ACK报文,服务端状态就变成了建立连接。
  • FIN-WAIT-1是指首先希望关闭TCP连接的一端的状态,当这一段发送FIN报文并等待ACK报文时,它就处于这个状态下。当这一端接受到ACK报文时,它的状态就变成了FIN-WAIT-2。
  • FIN-WAIT-2是指已经关闭自己这端TCP连接的一端等待接受另一端FIN报文的状态。等到接受到另外一端的FIN报文,它的状态就会变成TIME-WAIT。
  • CLOSE-WAIT是指首先收到FIN报文一端的状态,这一端知道另一端已经要关闭TCP连接了,但是自己这一端还未关闭TCP。
  • LAST-ACK是指首先收到FIN报文一端的状态,这一端也要关闭TCP连接了,并且向另一端发送了FIN报文。

    sequence number和acknowledge number

     sequence number(之后简称为seq)是用来标识从TCP发端到TCP收端发送的数据字节流,它表示在这个报文段中的第一个数据字节的序号。第一条报文的seq为TCP协议自己计算出来的数值ISN,以后的报文的seq为INS加上已经发送数据的长度,比如第一条报文的seq为x,length为100,那么下一条带有数据的报文的seq为x+101。
     而acknowledge number(之后简称为ack)是表示发送确认的一端所期望收到的下一个序号,因此ack是上次成功接收报文的seq数值加一。只有ACK标志为1时,ack才有效。需要注意的是,TCP有些报文是不包含数据字节流信息的,那么它就不会影响到下一个报文的seqence number。在上一端的例子中,一端接受到这个seq为x,长度为100的报文之后,需要发送一个带有ACK标志的报文,其ack值为x+101。

    TCP建立连接和关闭连接

     TCP建立连接和关闭连接是TCP协议中比较重要的一部分,也是面试经常会涉及的部分,我们在这里就来详细讲解一下TCP建立连接和关闭连接过程中的每一步报文和其目的。
    TCP建立和关闭连接

 TCP建立连接和关闭连接的过程也被称为三次握手和四次握手,其中涉及两军通讯问题。因为网络通讯是不可靠的,所以你无法知道自己发送的报文另外一端是否收到,所以必须等待对方发送一个确认接受的报文;对于另外一方也是如此,另外一方也不清楚自己发送的确认接受报文是否被接受到,所以也希望对方再发送一个确认报文。但是在不可靠的通信中,不管几次握手(发送报文)都是有风险的,因为永远无法确认最后一次通信被送达。一般来说,握手次数达到3就可以保证通信信息被正确传达。

 客户端首先发送一个带有SYN标志的报文给服务端,seq为ISN,就是初始化的Sequence Number。如图所示,client发送的SYN报文的seq为x。客户端发送这个报文的目的是通知服务端自己希望建立一个TCP连接。
 服务端接受到客户端发送的SYN报文,需要返回一个带有SYN和ACK标志的报文,它的seq为服务器端计算获得的ISN,也就是y。它的ack数值是已经收到报文的seq数值+1,也就是x+1。服务器端发送这个报文来通知客户端自己已经收到客户端希望建立连接的报文,并且同意建立连接。
 客户端接受到服务端的报文,发送一个带有ACK标志的报文,它的ack数值为y+1。客户端发送这个报文是为了通知服务端自己已经收到了它的报文,可以进行数据传输了。客户端发送完这个报文之后,默认TCP连接已经建立,就可以直接开始发送数据报文了。
 服务端接受到客户端发送的ACK报文之后,就可以直接发送数据啦。

 由于TCP是全双工的协议,也就是说两端可以同时进行数据传输,所以,TCP连接的关闭在两端都关闭之后才正式关闭。当一端已经没有可以传输的数据时,就会发送带有FIN标记的报文,向另一端表示自己不会在传输数据啦。接受到另一端的ack报文之后,这一端就不会在发送数据报文(也就是tcp负载)了。但是ack等控制信息报文还是会发送的。也就是说,两端的FIN报文不一定是连在一起的,服务端可能很早就发送FIN报文了,但是客户端可以在服务端发送FIN报文之后继续发送数据报文,然后在发送FIN报文。
 如图所示,client先发送带有FIN标志的报文给服务端,表面自己这端已经无数据可以发送了,希望关闭TCP连接。报文的seq为x+2,ack为y+1。
 服务端接受到这个报文之后发送带有ACK标志的报文,其ack为(x+2)+1,也就是x+3。
 服务端无数据发送之后,也向客户端发送带有FIN标志的报文,seq为y+1。
 客户端接受到该报文之后,发送一个带有ACK标志的报文,其ack为y+2。

1000 Share