现在的位置: 首页 > 综合 > 正文

[详解]TCP三次握手,四次分手

2019年05月17日 ⁄ 综合 ⁄ 共 4565字 ⁄ 字号 评论关闭

TCP是TCP/IP体系中非常复杂的一个协议。下面首先介绍TCP最主要的特点:

(1)TCP是面向连接的运输层协议。这就是说,应用程序在使用TCP协议之前,必须先建立TCP连接。在传送数据完成后,必须释放已经建立的TCP连接。

(2)每一条TCP连接只有两个端点,每个TCP连接只能是点对点的。

(3)TCP提供可靠交付的服务。也就是说,通过TCP连接传输数据,无差错、不丢失、不重复、并且按照序列到达。

(4)TCP提供全双工通信。TCP允许通信双方的应用应用进程在任何时候都能发送数据,TCP连接的两端都有发送缓存和接收缓存,用来临时存放双向通信的数据。在发送时,应用程序把数据传给TCP的缓存后,就做自己的事去了,而TCP在合适的时候就把数据发送出去。在接收时,TCP把数据放入缓存,上层的应用程序在合适的时候读取缓冲中的数据。

(5)面向字节流。TCP中的流指的是流入到进程和从进程流出的字节序列。“面向字节流”的含义是:虽然应用程序和TCP的交互是一块一块的数据块(大小不等),但TCP把应用程序交下来的数据看成仅仅是一连串的无结构的字节流,TCP并不知道所传字节流的含义。TCP不保证接收方应用程序所收到的数据块和发送方应用程序所发的数据块具有相同的大小。但是接收方应用程序收到的字节流必须和发送方应用程序发出的字节流完全一样。当然接收方的应用程序必须具有识别收到字节流的能力,把它还原成有意义的应用层数据。

TCP报文段的首部格式:

        TCP虽然是面向字节流的,但是TCP传输的数据单元确实报文段。一个TCP报文段分为首部和数据两部分,而TCP的全部功能都体现在它的首部中各字段的作用。TCP报文段首部的前20个字节是固定的,后面有4N个字节是根据需要而增加的选项(N是整数)。因此TCP首部的最小长度就是20个字节。

                                             

首部各字段的意义如下:

(1)源端口和目的端口:各占两个字节,分别写入源端口号和目的端口号。TCP的分用功能就是通过端口实现的。

(2)序号:占四个字节。共2^32个序号,序号增加到2^32-1后,下一个序号就又回到了0.也就是说,序号使用mod2^32运算。在一个TCP连接中传送的字节流中的每一个字节都按顺序编号。整个要传送的字节流的起始序号必须在建立连接时设定。首部中的序号字节段值则是指的是本报文段送发送的数据的第一个字节的序号。这个字段的名称也叫“报文段序号”。

(3)确认号:占4个字节,是期望收到对方下一个报文段和第一个数据字节的序号。
若确认序号 = N,子表明序号N-1为止的数据都已经正确收到。

(4)数据偏移:占4位,它指出TCP报文段的数据起始处距离TCP报文段处的距离,这个字段实际上是指TCP报文段的首部长度。

(5)保留:占6位,保留为今后使用,但是目前应置为0。

(6)紧急URG:当URG=1时,表明紧急指针字段有效。它告诉系统此报文段中有紧急数据,应尽快传送(相当与优先级高的数据),而不是按照原来的排队顺序开传送。

(7)确认ACK:仅当ACK=1时确认信号字段有效。当ACK=0时确认无效。TCP规定,在连接建立后所有传送的报文段必须把ACK置为1.

(8)推送PUSH:当两个应用程序进行交互式通信时,有时在一端的应用进程希望在键入一个命令后立即就能够收到对方的响应。在这种情况下,TCP就可以推送操作。

(9)复位RET:当RST=1时,表明TCP连接中出现严重的错误,必须释放连接,然后再重新建立传输连接。RST置1还用开拒绝一个非法的报文段后者拒绝打开一个连接。

(10)同步SYN:在连接建立时用来同步的序号。

(11)终止FIN:用开释放一个连接。当FIN=1时,表明此报文段的发送方的数据已经发送完毕,并要求释放运输连接。

(12)窗口:占2个字节。窗口指的是发送本报文段的一方的接收窗口。窗口值告诉对方:本报文段首部中的确认号算起,接收方目前允许对方发送的数据数量。之所以要有这个限制,是因为接收方的数据缓存空间是有限的。总之,窗口值作为接收方让发送方设置发送窗口的依据。(窗口值是经常动态变化的)

(13)检验和:占2个字节。检验和的字段检验的范围包括首部和数据部分,在计算的时候,要在TCP报文段的首部加上12字节的伪首部。

(14)紧急指针:占2个字节。紧急指针适当URG=1时才有意义,它指出本报文段中的紧急数据的字节数(紧急数据结束后就是普通的数据),因为紧急指针指出了紧急数据的末尾在报文段的位置,当所有紧急数据处理完成后,TCP就告诉应用程序恢复正常操作。值的注意的是:当窗口值为0时也可以发送紧急数据。

(15)选项:长度可变,最长可达40字节。当没有使用选项时,TCP首部长度是20字节。

TCP的传输连接管理

        TCP是面向连接的协议。运输连接是用传送TCP报文的,TCP传输建立和释放是每一次面向连接的通信中必不可少的过程。因此,运输连接就有三个阶段,即:连接建立、数据传输和连接释放。运输连接的管理就是使运输连接的建立和释放能正常地进行。
下图是连接建立、数据传输和连接释放的整体图解过程:

                                                              

1、TCP建立连接
假定A运行的是TCP客户程序,而B运行的TCP服务器程序。最初两端的TCP进程都处于CLOSED(关闭)状态。注意:A主动打开连接,B被动打开连接。

                                           

        B的TCP服务器进程首先创建传输控制块TCB,准备接收客户端进程的连接请求,然后服务器进程就处于LISTEN(监听)状态,等待客户端的连接请求。如有,就会立即作出响应。

(1)A的TCP客户进程也是首先创建传输控制块TCB,然后向B发出连续请求报文,这时首部中同步序号SYN=1,同时选择一个初始序号seq = x。TCP规定,SYN报文段不能携带数据,但是要消耗一个序号。这时,TCP客户进程进入SYN-SENT(同步已发送)状态。

(2)B收到连接报文请求报文段后,如果同意建立连接,则向A发送确认。在确认报文段中应把SYN位和ACK位都置为1,确认号ack = x +1,同时也为自己选择一个初始序号seq = y。请注意,这个报文段也不能携带数据,但是同样要消耗一个序号,这时TCP服务器进程进入SYN-RCVD(同步收到)状态。

(3)TCP客户进程收到B的确认后,还要向B给出确认。确认报文段的ACK置1,确认号ack = y+1,而自己的序号seq = x +1。TCP标准规定,ACK报文段可以携带数据,如果不携带数据则不会消耗序号,在这种情况下,下一个数据报文段的序号仍是seq = x + 1。这时,TCP连接已经建立A和B都进入ESTABLISHED状态。
上面连接建立的过程叫做三次握手。

A和B之间进行连接的三次握手可以该为两次握手吗?为什么?

      不能。这主要是为了防止已失效的连接请求报文段突然有传到B,因而产生错误。

       现在假定出现这样一种异常情况,即A发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间滞留了,以致延误到连接释放以后某个时间才到达B,本来这是一个早已失效的报文,但是B收到此失效的连接请求报文段后,就误认为是A又发出一次新的连接请求。于是就向A发出确认报文段,同意建立连接。假定不采用三次握手,那么只要B发出确认,新的连接就建立好了。由于现在A并没有发出连接请求,因此不会理睬B的确认,也不会向B发送数据。但是B确以为间的运输连接已经建立了,并一直等待A发来的数据。B的许多资源就这样浪费了。采用三次握手的办法可以防止这样的现象发生。

2、TCP的连接释放

                                       

(1)数据传输结束后,通信的双方都可以释放连接。现在A和B都处于ESTABLISHED状态。A进程先向其TCP发出连接释放报文段,并停止再发送数据,主动关闭TCP连接。A把连接释放报文段首部的FIN置为1,其序号seq = u,它等于前面已经传送过的数据最后一个字节的序号加1。这时A进入FIN-WAIT-1(终止等待1)状态,等待B的确认。请注意,TCP规定,FIN报文即使不携带数据,它也会消耗一个序号。

(2)B收到连接报文段后即发出确认,确认号是ack = u + 1,而这个报文段自己的序号是v,等于B前面已传送过的数据的最后一个字节的序号加1。然后B就进入CLOSE-WAIT(关闭等待)状态。TCP服务器进程这时应该通知上层的应用进程,因而从A到B的这个连接就释放了,这时的TCP连接处于半关闭状态,即A已经没有数据要发送了,但是B要发送数据,A仍然要接收。也就是说,从B到A这个方向的连接并没有关闭。这个状态还会持续一段时间。
    A收到B的确认后,就进入FIN-WAIT-2(终止等待2)状态,等待B发出连接释放报文。

(3)若B已经没有数据要给A发送,其应用进程就通知TCP释放连接。这时B发出的连接释放报文段必须使FIN = 1。现在假定B的序号为w,B还必须重复上次发送的确认号ack = u + 1。这时B就进入LAST-ACK(最后确认)状态,等待A的确认。

(4)A收到B的连接释放报文段后,必须对此发出确认。在确认报文段中把ACK置为1,确认号ack = w + 1,而自己的序号是seq = u + 1。然后进入到TIME-WAIT(时间等待)状态。请注意,现在TCP连接还没有释放掉。必须经过时间等待计时器设置时间2MSL后,A才进入到CLOSED状态。时间 MSL叫做最长报文段寿命。

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

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

TIME-WAIT状态是什么?为什么会有TIME-WAIT状态?如何避免TIME-WAIT状态占用的资源?

TIME-WAIT状态:客户端连接在收到服务器的结束报文段之后,并没有直接进入CLOSE状态,而是转移到TIME-WAIT状态。在这个状态,客户端连接要等待2MSL才会进入关闭状态。

TIME-WAIT状态存在的原因:

(1)可靠的终止TCP连接

(2)保证让迟来的TCP报文段有足够的时间识别并丢弃(当一个TCP连接处于TIME-WAIT状态时,我们将无法立即使用该连接占用着的端口号建立一个新连接)

避免TIME-WAIT状态:可以通过socket选项SD_REUSEADDR来强制进程立即使用处于TIME-WAIT状态的连接占用的端口。

3、状态转换图

                                                          

                                                                                                                                                                                    (相关图片引自百度图片)

抱歉!评论已关闭.