网络协议TCP连接的建立和释放

Posted phlsheji

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网络协议TCP连接的建立和释放相关的知识,希望对你有一定的参考价值。

转载请注明出处:http://blog.csdn.net/ns_code/article/details/29382883


TCP首部格式

    先看TCP报文段的格式,例如以下;

技术分享

    TCP报文段首部的前20个字节是固定的,后面有4N字节是依据须要而添加的选项。因此TCP报文段的最小长度为20个字节。

    首部固定部分的各字段的意义例如以下:

    1、源port和目的port:加上IP首部的源IP地址和目的IP地址,确定唯一的一个TCP连接。另外通过目的port来决定TCP将数据报交付于那个应用程序,从而实现TCP的分用功能。

    2、序号:占4个字节,序号的范围为[0,4284967296]。由于TCP是面向字节流的,在一个TCP连接中传送的字节流中的每个字节都按顺序编号,首部中的序号字段则是指本报文段所发送的数据的第一个字节的序号。另外,序号是循环使用的,当序号添加到最大值时,下一个序号就又回到了0。

    3、确认号:当ACK标志位为1时有效,表示期望收到的下一个报文段的第一个数据字节的序号。确认号为N。则表明到序号N-1为止的全部数据字节都已经被正确地接收到了。

    4、头部长度:TCP报文段的头部长度。它指出TCP报文段的数据部分的起始位置与TCP报文段的起始位置的距离。

头部长度占4个字节。但它的单位是32位字。即以4字节为计算单位,因此头部长度的最大值为15*4=60个字节。这就意味着选项的长度不超过40个字节。

    5、保留位:必须为0.

    6、以下的六个控制位说明报文段的性质:

    1)URG:与首部中的紧急指针字段配合使用。URG为1时,表明紧急指针字段有效,发送应用进程告诉发送方的TCP有紧急数据要传送,于是发送方TCP就把紧急数据插入到本报文段数据的最前面。而其后面仍是普通数据。

    2)ACK:仅当ACK=1时确认号字段才有效,当ACK=0时。确认号无效。

TCP规定,在连接建立后全部的传送报文段都必须把ACK置1。

    3)PSH:假设发送的报文段中PSH为1。则接收方接受到该报文段后。直接将其交付给应用进程,而不再等待整个缓存都填满后再向上交付。

    4)RST:复位标志,RST=1时,表明TCP连接中出现严重差错,必须释放连接,然后又一次建立运输连接。

    5)SYN:同步序号,用来发起一个连接。当SYN=1而ACK=0时,表明这是一个连接请求报文段,若对方允许建立连接,则应在响应的报文段中使SYN=1和ACK=1。

    6)FIN:用来释放一个连接。

当FIN=1时,表明此报文段的发送方的数据已发送完成。并要求释放连接。

    7、窗体:接收方让发送方下次发送报文段时设置的发送窗体的大小。

    8、校验和:校验的字段范围包含首部和数据这两部分。

    9、紧急指针:紧急指针当URG=1时才有效。它指出本报文段中的紧急数据的字节数。值得注意的是。即使窗体为0时,也可发送紧急数据。

    10、选项与填充:选项应该为4字节的整数倍,否则用0填充。最常见的可选字段是最长报文大小MSS(Maximum Segment Size),每个连接方通常都在通信的第一个报文段中指明这个选项。它指明本端所能接收的最大长度的报文段。该选项假设不设置。默觉得536(20+20+536=576字节的IP数据报)。当中ip首部和tcp首部各20个字节,而internet 上标准的MTU (最小)为576B。

  


TCP连接的建立

    下图为TCP三次握手连接的建立过程:

技术分享

    服务端的TCP进程先创建传输控制块TCB,准备接受client进程的连接请求,然后服务端进程处于LISTEN状态,等待client的连接请求,如有。则作出响应。

    1、client的TCP进程也首先创建传输控制模块TCB。然后向服务端发出连接请求报文段,该报文段首部中的SYN=1,ACK=0,同一时候选择一个初始序号seq=i。TCP规定。SYN=1的报文段不能携带数据,但要消耗掉一个序号。

这时,TCP客户进程进入SYN—SENT(同步已发送)状态,这是TCP连接的第一次握手。

    2、服务端收到client发来的请求报文后,假设允许建立连接,则向client发送确认。确认报文中的SYN=1。ACK=1,确认号ack=i+1,同一时候为自己选择一个初始序号seq=j。相同该报文段也是SYN=1的报文段。不能携带数据。但相同要消耗掉一个序号。这时。TCP服务端进入SYN—RCVD(同步收到)状态,这是TCP连接的第二次握手。

    3、TCPclient进程收到服务端进程的确认后,还要向服务端给出确认。确认报文段的ACK=1。确认号ack=j+1,而自己的序号为seq=i+1。TCP的标准规定,ACK报文段能够携带数据,但假设不携带数据则不消耗序号。因此,假设不携带数据,则下一个报文段的序号仍为seq=i+1。这时,TCP连接已经建立。client进入ESTABLISHED(已建立连接)状态。这是TCP连接的第三次握手。能够看出第三次握手client已经能够发送携带数据的报文段了。

    当服务端收到确认后,也进入ESTABLISHED(已建立连接)状态。


    两方同一时候主动连接的TCP连接建立过程
    正常情况下,传输连接都是由一方主动发起的。但也有可能两方同一时候主动发起连接,此时就会发生连接碰撞。终于仅仅有一个连接能够建立起来。由于全部连接都是由它们的端点进行标识的。假设第一个连接请求建立起一个由套接字(x,y)标识的连接。而第二个连接也建立了这样一个连接,那么在TCP实体内部仅仅有一个套接字表项。


当出现同一时候发出连接请求时,则两端差点儿在同一时候发送一个SYN字段置1的数据段。并进入SYN_SENT状态。当每一端收到SYN数据段时,状态变为SYN_RCVD,同一时候它们都再发送SYN字段置1。ACK字段置1的数据段,对收到的SYN数据段进行确认。当两方都收到对方的SYN+ACK数据段后,便都进入ESTABLISHED状态。

图10-39显示了这样的同一时候发起连接的连接过程,但终于建立的是一个TCP连接,而不是两个。这点要特别注意。

技术分享
    从图中能够看出,一个两方同一时候打开的传输连接须要交换4数据段,比正常的传输连接建立所进行的三次握手多交换一个数据段。

此外要注意的是,此时我们没有将不论什么一端称为客户或server。由于每一端既是客户又是server。


    为什么一定要进行三次握手呢?

    前两次的握手非常显然是必须的。主要是最后一次。即client收到服务端发来的确认后为什么还要想服务端再发送一次确认呢?这主要是为了防止已失效的请求报文段突然又传送到了服务端而产生连接的误判。

    考虑例如以下的情况:client发送了一个连接请求报文段到服务端,可是在某些网络节点上长时间滞留了。而后client又超时重发了一个连接请求报文段该服务端,而后正常建立连接。传输数据完成。并释放了连接。

假设这时候第一次发送的请求报文段延迟了一段时间后,又到了服务端,非常显然,这本是一个早已失效的报文段。可是服务端收到后会误以为client又发出了一次连接请求,于是向client发出确认报文段,并允许建立连接。假设不採用三次握手,这时服务端仅仅要发送了确认,新的连接就建立了,但由于client比你更没有发出建立连接的请求,因此不会理会服务端的确认,也不会向服务端发送数据,而服务端却觉得新的连接已经建立了。并在一直等待client发送数据,这样服务端就会一直等待下去。直到超出保活计数器的设定值。而将client判定为出了问题。才会关闭这个连接。这样就浪费了非常多server的资源。而假设採用三次握手。client就不会向服务端发出确认,服务端由于收不到确认,就知道client没有要求建立连接。从而不建立该连接。


TCP连接的释放

    下图为TCP四次挥手的释放过程:

技术分享

    传输数据结束后。通信的两方都能够释放连接,并停止发送数据。假设如今client和服务端都处于ESTABLISHED状态。

    1、clientA的TCP进程先向服务端发出连接释放报文段,并停止发送数据。主动关闭TCP连接。

释放连接报文段中FIN=1,序号为seq=u。该序号等于前面已经传送过去的数据的最后一个字节的序号加1。这时,A进入FIN—WAIT-1(终止等待1)状态。等待B的确认。TCP规定,FIN报文段即使不携带数据,也要消耗掉一个序号。这是TCP连接释放的第一次挥手。

    2、B收到连接释放报文段后即发出确认释放连接的报文段。该报文段中,ACK=1,确认号为ack=u+1。其自己的序号为v,该序号等于B前面已经传送过的数据的最后一个字节的序号加1。

然后B进入CLOSE—WAIT(关闭等待)状态,此时TCPserver进程应该通知上层的应用进程,因而A到B这个方向的连接就释放了,这时TCP处于半关闭状态。即A已经没有数据要发了,但B若发送数据,A仍要接受,也就是说从B到A这个方向的连接并没有关闭,这个状态可能会持续一些时间。这是TCP连接释放的第二次挥手。

    3、A收到B的确认后,就进入了FIN—WAIT(终止等待2)状态,等待B发出连接释放报文段。假设B已经没有要向A发送的数据了。其应用进程就通知TCP释放连接。这时B发出的链接释放报文段中,FIN=1,确认号还必须反复上次已发送过的确认号。即ack=u+1,序号seq=w,由于在半关闭状态B可能又发送了一些数据,因此该序号为半关闭状态发送的数据的最后一个字节的序号加1。

这时B进入LAST—ACK(最后确认)状态。等待A的确认,这是TCP连接的第三次挥手。

    4、A收到B的连接释放请求后,必须对此发出确认。确认报文段中,ACK=1,确认号ack=w+1,而自己的序号seq=u+1,而后进入TIME—WAIT(时间等待)状态。这时候。TCP连接还没有释放掉,必须经过时间等待计时器设置的时间2MSL后,A才进入CLOSED状态,时间MSL叫做最长报文寿命,RFC建议设为2分钟,因此从A进入TIME—WAIT状态后,要经过4分钟才干进入到CLOSED状态,而B仅仅要收到了A的确认后,就进入了CLOSED状态。二者都进入CLOSED状态后,连接就全然释放了,这是TCP连接的第四次挥手。


    两方主动关闭的TCP连接释放流程

    与能够两方同一时候建立TCP传输连接一样。TCP传输连接关闭也能够由两方同一时候主动进行(正常情况下都是由一方发送第一个FIN数据段进行主动连接关闭,还有一方被动接受连接关闭)

技术分享

    当两端相应的网络应用层进程同一时候调用CLOSE原语,发送FIN数据段运行关闭命令时,两端均从ESTABLISHED状态转变为FIN WAIT 1状态。随意一方收到对端发来的FIN数据段后。其状态均由FIN WAIT 1转变到CLOSING状态,并发送最后的ACK数据段。

当收到最后的ACK数据段后。状态转变化TIME_WAIT,在等待2MSL后进入到CLOSED状态。终于释放整个TCP传输连接。


    为什么A在TIME—WAIT状态必须等待2MSL时间呢?

    1、为了保证A发送的最后一个ACK报文段能够到达B。该ACK报文段非常有可能丢失。因而使处于在LIST—ACK状态的B收不到对已发送的FIN+ACK报文段的确认,B可能会重传这个FIN+ACK报文段,而A就在这2MSL时间内收到这个重传的FIN+ACK报文段。接着A重传一次确认。又一次启动2MSL计时器。最后A和B都进入CLOSED状态。假设A在TIME—WAIT状态不等待一段时间就直接释放连接,到CLOSED状态,那么久无法收到B重传的FIN+ACK报文段。也就不会再发送一次确认ACK报文段,B就无法正常进入CLOSED状态。

    2、防止已失效的请求连接出如今本连接中。

在连接处于2MSL等待时。不论什么迟到的报文段将被丢弃。由于处于2MSL等待的、由该插口(插口是IP和port对的意思。socket)定义的连接在这段时间内将不能被再用,这样就能够使下一个新的连接中不会出现这样的旧的连接之前延迟的报文段。

    补充:

    当client运行主动关闭并进入TIME—WAIT是正常的,服务端运行被动关闭,不会进入TIME—WAIT状态。这说明,假设终止了一个客户程序,并马上重新启动该客户程序。则新的客户程序将不再重用相同的本地port,而是使用新的port,这不会带来什么问题。由于client使用本地port,而并不关心这个port是多少。

但对于server来说。情况就不同了,server总是用我们熟知的port。那么在2MSL时间内,重新启动server就会出错。为了避免这个错误,server给出了一个平静时间的概念,这是说在2MSL时间内,尽管能够又一次启动server,可是这个server还是要平静的等待2MSL时间的过去才干进行下一次连接。

    

    

    


以上是关于网络协议TCP连接的建立和释放的主要内容,如果未能解决你的问题,请参考以下文章

计算机网络-5-传输层

TCP协议分析

TCP协议分析

【网络协议笔记】第四层:传输层(Transport)TCP协议简介(1)

TCP协议分析

TCP协议分析