在谈及TCP创建链接和释放链接过程,先来简单认识一下TCP报文段首部格式的的几个名词(这里只是简单说明,具体请查看相关教程)服务器
序列号seq (Sequence Number) :占4个字节,用来标记数据段的顺序,TCP把链接中发送的全部数据字节都编上一个序号,第一个字节的编号由本地随机产生;给字节编上序号后,就给每个报文段指派一个序号;序列号seq就是这个报文段中的第一个字节的数据编号。
确认号ack (Acknowledgement Number) :占4个字节,期待收到对方下一个报文段的第一个数据字节的序号;序列号表示报文段携带数据的第一个字节的编号;而确认号指的是指望接收到下一个字节的编号;所以当前报文段最后一个字节的编号+1即为确认号。
确认ACK:占1位,仅当ACK=1时,确认号字段才有效。ACK=0时,确认号无效
同步SYN:链接创建时用于同步序号。当SYN=1,ACK=0时表示:这是一个链接请求报文段。若赞成链接,则在响应报文段中使得SYN=1,ACK=1。所以,SYN=1表示这是一个链接请求,或链接接受报文。SYN这个标志位只有在TCP建产链接时才会被置1,握手完成后SYN标志位被置0。
终止FIN(Finish):用来释放一个链接。FIN=1表示:此报文段的发送方的数据已经发送完毕,并要求释放运输链接网络
PS:ACK、SYN和FIN这些大写的单词表示标志位,其值要么是1,要么是0;ack、seq小写的单词表示序号。并发
1、TCP创建链接三次握手spa
(1)、三次握手的过程.net
1)主机A向主机B发送TCP链接请求数据包,其中包含主机A的初始序列号seq(A)=x。(其中报文中同步标志位SYN=1,ACK=0,表示这是一个TCP链接请求数据报文;序号seq=x,代表传输数据时的第一个数据字节的序号是x);blog
2)主机B收到请求后,会发回链接确认数据包。(其中确认报文段中,标识位SYN=1,ACK=1,表示这是一个TCP链接响应数据报文,并含主机B的初始序列号seq(B)=y,以及主机B对主机A初始序列号的确认号ack(B)=seq(A)+1=x+1)教程
3)第三次,主机A收到主机B的确认报文后,还需做出确认,即发送一个序列号seq(A)=x+1;确认号为ack(A)=y+1的报文;进程
(2)为何须要第三次握手?资源
还要再发送一次确认是为了,防止已失效的链接请求报文段忽然又传到了B,于是产生错误。
已失效的报文段:正常状况下:A发出链接请求,但由于丢失了,故而不能收到B的确认。因而A从新发出请求,而后收到确认,创建链接,数据传输完毕后,释放链接,A发了2个,一个丢掉,一个到达,没有“已失效的报文段”
可是,某种状况下,A的第一个在某个节点滞留了,延误到达,原本这是一个早已失效的报文段,可是在A发送第二个,而且获得B的回应,创建了链接之后,这个报文段居然到达了,因而B就认为,A又发送了一个新的请求,因而发送确认报文段,赞成创建链接,倘若没有三次的握手,那么这个链接就创建起来了(有一个请求和一个回应),此时,A收到B的确认,但A知道本身并无发送创建链接的请求,由于不会理睬B的这个确认,因而呢,A也不会发送任何数据,而B呢却觉得新的链接创建了起来,一直等待A发送数据给本身,此时B的资源就被白白浪费了。可是采用三次握手的话,A就不发送确认,那么B因为收不到确认,也就知道并无要求创建链接。同步
简而言之:第三次握手,主机A发送一次确认是为了防止:若是客户端迟迟没有收到服务器返回的确认报文,这时他会放弃链接,从新启动一条链接请求;但问题是:服务器不知客户端没收到,因此他会收到两个链接请求,白白浪费了一条链接开销。
2、TCP释放链接四次握手
(1)四次握手过程
假设主机A为客户端,主机B为服务器,其释放TCP链接的过程以下:
1) 关闭客户端到服务器的链接:首先客户端A发送一个FIN,用来关闭客户到服务器的数据传送,而后等待服务器的确认。其中终止标志位FIN=1,序列号seq=u
2) 服务器收到这个FIN,它发回一个ACK,确认号ack为收到的序号加1。
3) 关闭服务器到客户端的链接:也是发送一个FIN给客户端。
4) 客户段收到FIN后,并发回一个ACK报文确认,并将确认序号seq设置为收到序号加1。
首先进行关闭的一方将执行主动关闭,而另外一方执行被动关闭。
主机A发送FIN后,进入终止等待状态, 服务器B收到主机A链接释放报文段后,就当即给主机A发送确认,而后服务器B就进入close-wait状态,此时TCP服务器进程就通知高层应用进程,于是从A到B的链接就释放了。此时是“半关闭”状态。即A不能够发送给B,可是B能够发送给A。
此时,若B没有数据报要发送给A了,其应用进程就通知TCP释放链接,而后发送给A链接释放报文段,并等待确认。A发送确认后,进入time-wait,注意,此时TCP链接尚未释放掉,而后通过时间等待计时器设置的2MSL后,A才进入到close状态。
(2)为何要等待2MSL呢?
MSL即Maximum Segment Lifetime,也就是最大报文生存时间,他是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。引用《TCP/IP详解》中的话:“它(MSL)是任何报文段被丢弃前在网络内的最长时间”。RFC 793中规定MSL为2分钟,实际应用中经常使用的是30秒,1分钟和2分钟等。
TCP的TIME_WAIT状态须要等待2MSL,当TCP的一端发起主动关闭,在发出最后一个ACK包后,即第3次握手完成后发送了第四次握手的ACK包后就进入了TIME_WAIT状态,必须在此状态上停留两倍的MSL时间,等待2MSL时间主要目的是怕最后一个ACK包对方没收到,那么对方在超时后将重发第三次握手的FIN包,主动关闭端接到重发的FIN包后能够再发一个ACK应答包。在TIME_WAIT状态时两端的端口不能使用,要等到2MSL时间结束才可继续使用。当链接处于2MSL等待阶段时任何迟到的报文段都将被丢弃。不过在实际应用中能够经过设置SO_REUSEADDR选项达到没必要等待2MSL时间结束再使用此端口。
归纳缘由以下:
①、为了保证A发送的最后一个ACK报文段可以到达B。即最后这个确认报文段颇有可能丢失,那么B会超时重传,而后A再一次确认,同时启动2MSL计时器,如此下去。若是没有等待时间,发送完确认报文段就当即释放链接的话,B就没法重传了(链接已被释放,任何数据都不能出传了),于是也就收不到确认,就没法按照步骤进入CLOSE状态,即必须收到确认才能close。
②、防止“已失效的链接请求报文段”出如今链接中。通过2MSL,那些在这个链接持续的时间内,产生的全部报文段就能够都从网络中消失。即在这个链接释放的过程当中会有一些无效的报文段滞留在楼阁结点,可是呢,通过2MSL这些无效报文段就确定能够发送到目的地,不会滞留在网络中。这样的话,在下一个链接中就不会出现上一个链接遗留下来的请求报文段了。
能够看出:B结束TCP链接的时间比A早一点,由于B收到确认就断开链接了,而A还得等待2MSL.
(3)为何TCP释放链接须要四次?
TCP创建链接要进行三次握手,而断开链接要进行四次。这是因为TCP的半关闭形成的。由于TCP链接是全双工的(即数据可在两个方向上同时传递)因此进行关闭时每一个方向上都要单独进行关闭。这个单方向的关闭就叫半关闭。当一方完成它的数据发送任务,就发送一个FIN来向另外一方通告将要终止这个方向的链接。
注意:
1)发送了FIN只是表示这端不能继续发送数据(应用层不能再调用send发送),可是还能够接收数据。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP链接在收到一个FIN后仍能发送数据,好比:如主机A收到主机B的FIN断开TCP链接请求,只是表示主机B已经发送完数据,主机A收到FIN后做出应答,并终止这个方向的数据传输,此时处于半关闭状态。可是主机A仍然能够发送数据的,只有当主机A发送完数据并发送FIN给主机B时,主机B才中止这个方向的数据传输,并关闭TCP链接。
2)在不少时候,TCP链接的断开都会由TCP层自动进行,例如你CTRL+C终止你的程序,TCP链接依然会正常关闭,你能够写代码试试。