TCP三次握手详解:传输控制块TCB以及积极和消极的连接建立方式

2019-07-29 19:30:41 浏览数 (1)

TCP协议目的是为了保证数据能在两端准确连续的流动,可以想象两个建立起TCP通道的设备就如同接起了一根水管,数据就是水管中的水由一头流向另一头。然而TCP为了能让一个设备连接多根“水管”,让一个设备能同时与多个设备交互信息,它必须要保证不同水管之间不会产生串联或相互影响,一根水管中的水绝不能流入另一根水管,要保证这样的效果,TCP协议使用socket数据结构来实现不同设备之间的连接。

socket包含两个成分,一个是IP地址,一个是端口号。同一个设备可以对应一个IP端口,但不同的“水管”用不同的端口号区分开来,于是同一个设备发送给其他不同设备的信息就不会产生混乱。在同一时刻,设备可能会产生多种数据需要分发给不同的设备,为了确保数据能够正确分发,TCP用一种叫做TCB,也叫传输控制块的数据结构把发给不同设备的数据封装起来,我们可以把该结构看做是信封。

一个TCB数据块包含了数据发送双方对应的socket信息以及拥有装载数据的缓冲区。在两个设备要建立连接发送数据之前,双方都必须要做一些准备工作,分配内存建立起TCB数据块就是连接建立前必须要做的准备工作。我们还需要了解的一点是TCP连接的建立方式,由于TCP协议建立在服务器—客户端的模式之上,因此对于两种不同角色的设备,他们发起连接的方式不一样。

客户端发起连接的方式叫Active Open。也就是客户端需要主动向服务器发送消息,表达自己想建立数据连接的请求,通常而言客户端会向服务器发送一个SYNC数据包。服务器发起连接的方式叫Passive Open,通来说服务器不可能知道当前时刻有哪个设备想向它发起连接,因此它只能构建一个端口,然后监听该端口,等待客户端从该端口向它发起连接请求。在OPEN阶段无论是客户端还是服务器都需要准备好TCB数据结构,但由于服务器不知道要连接它的客户端信息,因此在构建TCB模块时会默认将客户端对应的socket数据初始化为0.

当双方都把自己的socket和TCB数据结构准备好后,双方就可以进入所谓的“三次握手”连接建立过程,其基本流程如下图:

三次握手过程其实是为数据传输做一系列准备,第一个准备是客户端通知服务器它想建立连接;第二个过程是双方都得通知对方自己数据发送时的”初始序列号“ 这个号码用来标志数据包中所包含的数据顺序,后面我们会详解它的功能;第三个过程是实现参数交换,为了保证数据准确平稳的传输,双方都需要把自己的有关信息发送给对方,比如自己缓冲区的大小等。

TCP协议发送两种数据包,一种数据包用来传输数据,一种数据包用来发送控制信息,例如上图中的SYN,ACK等数据包就是用于控制目的。后面我们会看到TCP数据都会有一个包头,包头中有相应标志位,标志位的设定用于表明数据包是用于数据发送还是用于传输控制信息。

当标志位中的SYN位被启动时,它表明当前数据包的目的是为了实现双方数据状态同步,例如向对方告知自己的初始序列号以便对方知道如何接收自己发送过来的数据包。如果是ACK比特位被启动,它表明数据包用于通知接收方我收到了你上次发来的数据。还有很多比特位用于控制目的,例如FIN,RST,PSH,URG等。

于是所谓的三次握手建立连接,其实是客户端发送一个SYN数据包给服务器,在数据包中包含了自己的要发送数据包的初始序列号,服务器收到后回发一个数据包,其中SYN和ACK两个比特位都被启动,同时数据包中也包含了服务器发送数据的初始序列号,当客户端收到服务器发送的数据包后,它回发一个ACK包告诉服务器信息收到了,于是整个连接流程完毕,双方可以开始互发数据包。

这里有一个要点需要掌握的是,初始序列号往往是一个任意值而不是每次都以1开始,试想一次数据发送中,一方想对方发送了一个序列号为1的数据包,由于网络原因该数据包没有抵达对方,并且因为网络没有恢复,双方只好中断当前连接建立新连接。如果新连接同样用1作为初始序列号,当连接建立后,如果上次因网络原因没有抵达的数据包突然抵达了,那么对方就以为上次发送的数据包是这次新连接后发送过来的数据包,为了防止这种异常情况,我们需要将初始序列号设置为随机数。

当A把自己的初始化序列号放在SYN数据包中发送给B,B收到后会回发一个SYN ACK数据包,该数据包中B会把收到的来自A的序列号加一后的值发送回去,同时数据包中也包含B的初始化序列号,当A收到数据后发送一个ACK数据包其中包含了B发过来的序列号加一后所得的数值,其流程如下:

在TCP数据传输过程中往往需要通过控制数据包调整各种控制参数,在三次握手过程中,需要传输的控制参数为最大分片大小,也就是数据包中一次能发送的最大字节数,当要发送的数据大于该参数时,数据就必须分成若干小块分别发送。

下一节我们将用代码实现这三次握手功能,理论描述总是抽象,唯有通过代码实践才能将抽象的理论进行形象化的理解和把握。

0 人点赞