您的位置:首页 > 理论基础 > 计算机网络

TCP报文首部、三次握手与四次挥手以及四种定时器解析

2017-05-19 14:08 736 查看
关于TCP协议是网络中很重要的一个协议,这个协议自然需要好好看看。我们从TCP的首部来一点一滴的深入理解这个协议。

1. TCP首部介绍



源端口(source port)

16位的字段,定义了发送这个报文段的主机中的应用程序的端口号。

目的端口(destination port)

16位的字段,定义了接收这个报文段的主机中的应用程序的端口号。

序列号(sequence number)

32位的字段,定义了指派给本报文段第一个数据字节的编号。为了保证连接性,要发送的每一个字节都要编上号。序号可以告诉终点,报文段中的第一个字节是这个序列中的哪一个字节。

确认号(acknowledgment nimber)

确认号就是期望收到对方的下一个报文段的第一个数据字节的序号。当确认号位N,则表示N-1之前的数据都已经收到了。

首部长度(Hlen)(header length)

说明TCP报文段的首部长度,取值范围5-15,按照四字节对齐,所以首部长度范围也就是20字节-60字节。

保留位: 目前全为0,提供给以后使用

URG: URG为1的时候,此时紧急指针是有效的,此时会告诉操作系统此报文段有紧急数据,应当尽快传送,紧急数据说的就是数据从第一个字节到紧急指针的内容。不进入接收缓冲,就直接交给上层进程,其他数据都是要进入接收缓冲的。URG不进入缓冲。

ACK: ACK是用来确认的,当ACK为1的时候,确认字段有效,ACK为0,确认字段无效。

PSH: PSH是在两个应用的进程在进行通信的时候,当一方的进程希望输入命令以后立即就能够收到对方的响应,此时就使用PUSH。PSH=1,此时就立即创建一个报文发送出去,接收方收到这个报文段以后,直接交付给应用进程,不在等到整个缓存都填满了再向上交付。

RST:当该位有效时,表明 TCP 连接中出现严重错误,比如一方中途崩溃,或者网络极度拥塞,导致大面积丢包,数据长时间无法到达对方,则接下来的传输必须重新建立。该位还可以用来拒绝一个非法的报文段或拒绝打开一个连接。

SYN:当 SYN 被置为 1,而 ACK 为0时, 说明这是一个连接请求报文段,若对方同意建立连接,则应在应答报文中将 SYN 和 ACK 都置为 1。

FIN: 用来释放一个连接,FIN=1的时候,此时表示此报文段发送方数据全部发送完,释放连接。

窗口大小: 指的是发送本报文段的一方的接收窗口(不是自己的发送窗口),窗口值告诉对方,从本报文段首部中的确认号算起,接收方允许对方发送的的数据量。窗口字段明确指出了现在允许对方发送的数据量,窗口值是经常在动态变化着。

检验和: 用于检验TCP首部和TCP数据,同UDP一样检验的时候也需要加上伪首部进行检验。

紧急指针: 指出紧急数据范围,进行紧急操作,搭配URG,把紧急数据放入传送队列最前面传送出去

选项: 长度不固定,可以改变,最长可达40字节,选项SACK选择确认的时候可以使用,使用多个指针标注不连接序号的段落

注意: 一般来说TCP是要等到整个缓存都填满了后再向上交付,但是如果PSH=1的话,就不用等到整个缓存都填满,直接交付,但是这里的交付仍然是从缓冲区中交付的,URG是不要经过缓冲区的,千万记住!

TCP序列号和确定序号的作用:

1.重传机制(丢包)

2.按序到达

3.可以保证超时重传以及重传的序列号。

说完了整个TCP头部,现在我们来重点理解下PSH和URG这两个控制位

理解 PSH 标志之前,首先要知道 TCP 缓冲区的是如何工作的。TCP工作在在 OSI 模型中的第四次传输层,它对上层提供读取和写入的简单套接字,隐藏的数据之间通信分组的复杂性。为了允许应用程序随时从该套接字读取和写入,在接收方和发送方都有对应的缓冲区。

发送方和接受方:



当发送多个最大段大小(MSS)的数据(例如,传输大文件)时,缓冲器允许更有效地传输数据。然而,在处理一些要尽可能快地传输的实时应用程序时,大型缓冲区会带来危害。比如,我们在使用 ssh协议远程登录到服务器时。如果 TCP 一直等待,直到所输入的数据填满整个数据包才发送的话,发送一个两个字符的数据包,必须要先输入一千字符。太糟糕。

PSH 标志的作用就在这里,当PSH 被置为1 时, 会被立即推出,不会等待其他数据进入缓冲区。当接受端收到 PSH 被置 1 的数据包时,立即将该分段上交到对应的应用程序。即有如下作用:

通知发送方立即发送数据。
接收方立即将数据推送到应用程序。

 URG=1,表示紧急指针指向包内数据段的某个字节(数据从第一字节到指针所指向字节就是紧急数据)不进入缓冲区(一般不都是待发送的数据要先进入发送缓存吗?就直接交个上层进程,余下的数据都是要进入接收缓冲的;一般来说TCP是要等到整个缓存都填满了后在向上交付,但是如果PSH=1的话,就不用等到整个缓存都填满,直接交付,但是这里的交付仍然是从缓冲区交付的,URG是不要经过缓冲区的

2.TCP特点:

TCP面向连接

TCP面向字节流(面向字节流的意思是比如一次发送20个字节,接收的时候可以接收3个字节,5个字节,20个字节等等,UDP是面向数据报的,发送多少,就接收多少)

TCP保证可靠传输

TCP支持全双工通信

TCP支持端口到端口的连接,每一条TCP连接只能有两个端点

3.TCP的建立与释放:

(1)TCP的连接建立(三次握手)

TCP连接的建立,首先看下面的示意图:



首先我们需要知道TCP是客户机向服务器的请求,客户机是主动的打开连接,服务器是被动的打开连接。

B的服务器进程首先创建传输控制块TCB,准备接受客户进程的连接请求。然后服务器进程就处于LISTEN(收听)状态,扽带客户机的连接请求。接受到请求,做出响应。

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

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

客户机ATCP进程收到服务器B的确认以后,还需要给B给出确认,确认报文段ACK确认位为1,确认序号ack=y+1,而自己序号seq=x+1。ACK报文段可以携带数据。但是如果不携带数据则不消耗序号,接下来,TCP连接通过三次握手已经建立,客户机A进入ESTABLISHED(已建立连接)状态。

服务器B接收到A确认的报文段后,服务器B进入ESTABLISHED(已建立连接)状态。

为什么会采用三次握手,若采用二次握手可以吗? 四次握手可以吗?

采用三次握手是为了防止失效的连接请求报文段突然又传送到主机B,因而产生错误。失效的连接请求报文段是指:主机A发出的连接请求没有收到主机B的确认,于是经过一段时间后,主机A又重新向主机B发送连接请求,且建立成功,顺序完成数据传输。考虑这样一种特殊情况,主机A第一次发送的连接请求并没有丢失,而是因为网络节点导致延迟达到主机B,主机B以为是主机A又发起的新连接,于是主机B同意连接,并向主机A发回确认,新的连接就建立了,由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。所以只能最少采用三次握手,两次握手会出现问题。采用了三次握手,A就不会像B的确认发出确认,这样B就知道A没有要求建立连接,B就不会发送数据了。

大于等于三次握手都是可以的,但是浪费资源。

(2) TCP连接释放(四次挥手)



刚开始释放连接时,客户机A和服务器B都处于ESTABLISHED(已建立连接)状态。首先A应用进程首先向A的TCP发出连接释放报文段,并且停止再次发送数据,主动去关闭TCP连接。A把连接释放报文段的报文首部FIN终止位设置为1,然后序号seq=u,这个序号就是前面传送过的数据的最后一个字节的序号加1。FIN报文段不携带数据,只消耗一个序号。接下来A就进入FIN-WAIT-1(终止等待1)状态,等待服务器B的确认报文段。

服务器B收到了释放报文段以后向客户机A发送确认报文段,确认序号是ack=u+1,然后发送自己的序号seq=v。这个V上面的u一样,就是B传送过的数据的最后一个字节的序号加1。然后B就进入了CLOSE-WAIT(关闭等待)的状态,这样就相当于是关闭了A->B这个方向的连接,这个时候客户机只能接受B发来的数据,不能发送。所以下一步就是断开B->A方向上的连接。

A收到了B的确认报文段,然后A就转为了FIN-WAIT-2(终止等待2)状态。

经过关闭等待,B向A连接发送释放报文段,同样设置报文首部FIN终止位为1,B的序号变为seq=w(不是v主要是可能在关闭等待过程中可能发生了数据传送),确认序号ack=u+1,确认位设置为1,接下来,B就进入了LAST-ACK(最后确认)状态,等待A的确认。

A收到了B的连接释放报文段,需要对此发送确认报文段,设置确认位ACK=1,序号为u+1(第一次发送的链接释放报文消耗一个序号),确认序号ack=w+1,然后进入TIME-WAIT(时间等待)状态,这个时候并没有释放链接,通过时间等待计时器以后设置时间2MSL以后,A进入CLOSED(关闭)状态。最终A撤销了传输控制块TCB,结束了这次连接。

B收到A的确认报文段以后,就进入了CLOSED(关闭)状态,B同样撤销了传输控制块,结束了这次连接。并且因为时间等待的关系,B的结束要比A要早一点。

为什么TIME_WAIT状态还需要等2MSL后才能返回到CLOSED状态?

(1)这是因为虽然双方都同意关闭连接了,而且握手的4个报文也都协调和发送完毕,按理可以直接回到CLOSED状态(就好比从SYN_SEND状态到ESTABLISH状态那样);但是因为我们必须要假想网络是不可靠的,你无法保证你最后发送的ACK报文会一定被对方收到,因此对方处于
LAST_ACK状态下的SOCKET可能会因为超时未收到ACK报文,而重发FIN报文,所以这个TIME_WAIT状态的作用就是用来重发可能丢失的 ACK报文闭。防止因为客户机的ACK报文段的丢失导致服务器无法CLOSED。

(2)防止出现已失效的链接请求报文段出现在本次连接当中,客户机发送完ACK报文段,然后经过2MSL,就可以让本连接持续时间内所产生的所有的报文段都从网络当中消失。这样就可以使得下一个新的连接中不会出现这种旧的连接请求报文段。

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

这是因为服务端的LISTEN状态下的SOCKET当收到SYN报文的建连请求后,它可以把ACK和SYN(ACK起应答作用,而SYN起同步作用)放在一 个报文里来发送。但关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据都全部发送给对方了,所以你可以未必会马上会关闭SOCKET,也即你可能还需要发送一些数据给对方之后,再发送FIN报文给对方来表示你同意现在可以关闭连接了,所以它这里的ACK报文和FIN报文多数情况下都是分开发送的。

4.TCP/IP中的四种定时器

在TCP当中使用了四种定时器:

重传计时器

坚持计时器

保活计时器

时间等待计时器

重传定时器(Retransmission Timer): 为了控制丢失的报文段或丢弃的报文段,也是对报文段确认的等待时间,当TCP发送报文段,就创建这个待定报文段的重传定时器,当超时之前收到对报文段的确认,撤销计时器。若收到对报文段确认之前计时器超时,则重传报文,计时器被复位。

持续计时器(Persistent Timer): 持续计时器是在TCP的流量控制当中有提到,在流量控制当中,如果出现一种互相等待的死锁局面,这个时候就需要持续计时器,它专门为了对付零窗口通知设立的,当发送端收到零窗口确认,就启动持续计时器,当持续计时器截止期到的时候,这个时候发送端就会发送一个特殊的报文段,这个报文段叫做探测报文段,这个报文段只有一个字节的数据。探测报文段有序号,对方就在确认这个探测报文段的时候给出窗口值。如果窗口依然是零,那么收到这个报文段的一方就重新设置持续计时器,如果窗口不是零,就打破串口报文段丢失导致的死锁问题。

保活计时器(keeplive timer): 跟据TCP协议,当发送端和接收端都不主动释放一个TCP连接的时候,该连接将一直保持。即使一端出现了故障,由于另一端没有收到任何通知,TCP连接也会一直保持,这样就会造成TCP连接资源的浪费。所以有了保活定时器,保活计时器是每次在服务器接收到客户机发来的消息,就会被复位,超时通常设置为2小时,若服务器超过两小时还没有收到来自客户的信息,则就会发送探测报文段,若发送了10个探测报文段依然没有收到响应,服务器就认为客户到出问题,则终止链接,一次发送一个为75秒。

时间等待计时器(Time_Wait Timer): 时间等待计时器是在连接终止期使用,当客户TCP关闭连接的时候,此时并不认为这个链接就关闭了,此时必须经过设置时间的2MSL以后,才会进入关闭状态。剩下的上述关于2MSL有陈述,这里就不多说了。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息