连接管理
传输过程分为三个部分,连接建立,数据传输,连接释放。
连接建立
在建立连接时要考虑三个问题:首先要使连接双方相互知道对方的存在,除此之外,在连接的建立中允许连接的双方进行一些参数的交互,还有就是连接双方对于相关资源的分配准备。
三次握手
建立连接的过程是不对称的,分为主动连接的一方(客户端),和被动连接的一方(服务器),被动的一方一开始就要开启相关服务,进入监听状态(被动),以便可以获取客户端的连接请求,客户端在连接开始时主动打开相关的服务。
在握手的时候发送的报文段是比较特殊的,由于连接没有建立所以无法为上层提供服务,所以数据内容中不含有上层应用层有关的数据。
握手之前服务器处于监听状态(LISTEN)
第一次握手:也就是客户端发送一个报文,该报文的SYN字段被置为1,同时客户端选取一个起始序号放到报文中一并发过去。连接的一方向对方说明自己的存在。客户端进入请求连接(SYN-SENT)状态。
第二次握手:当服务器收到了数据包,就会从中提取处相应的SYN字段,这时服务器端这边就会开始为本次连接建立缓存与设置变量,这时服务器方面基本的条件已经快要满足了,同时其会发送一个数据包告知客户端自己的存在。这个数据报中的确认字段为客户端传来的序号加一,表示之前的信息收到了,同时服务器会选一个自己的起始序号放入报文序号段处,并将SYN字段置1。服务端进入(SYN-SENT)状态。
第三次握手:当客户端收到服务端的请求时,双方已经都收到了一个SYN字段为1的报文了,并且双方已经知道了对方的存在条件满足,这之后的传输报文中SYN字段将被置为0,收到报文后客户端也开始为这次连接分配缓存与设置变量,所有的条件都满足了,这时双方的所有准备工作结束,数据传输可以开始了,于是客户端开始第三次握手包的发送,其中的序号字段为之前的加一,确认字段为接受到的序号加一。客户端进入(ESTAB-LISTEN)状态。
当服务器端收到来自客户端的确认报文后,服务器也进入了(ESTAB-LISTEN)状态,连接建立,通知上层应用,数据传输开始。
连接释放
连接释放对应连接建立来看,也需要双方相互知道对方断开连接,同时还需要将之前连接时的相关缓存释放,相关变量回收。
TCP的半关闭状态
由于连接的传输过程是全双工的,所以连接的任一方均存在接收与发送,TCP的半关闭状态就是当一端停止发送后仍保留对数据的接收功能。
四次挥手
TCP连接是全双工的,因此每个方向都必须单独进行关闭。连接的释放可以是任一方发出,图中是客户端发出释放请求:
同样用于挥手的报文也是比较特殊的,由于连接准备释放,所以在释放连接的报文中也不包含有上层网络(应用层)的数据。
当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接,收到一个 FIN意味着这一方向上数据流动结束(接收到FIN报文后会关闭相应的读通道),而收到对方关于FIN的确认报文才说明这一方向上的数据通信完全结束。连接双方的释放的过程是完全对称的。
挥手之前双方都处于(ESTAB-LISTEN)状态。
第一次挥手:这里是客户端先提出释放(上层应用主动要求关闭),发送释放报文,释放报文的特点就在FIN字段置1,序号与确认号保留原有的规则,序号为之前得到的数据的最后一个字节的序号加一。进入终止等待1(FIN-WAIT-1)状态。
第二次挥手:服务器端接收到了来自客户端的请求释放的报文,这时服务器方已经知道了对方的释放请求。发出确认报文,报文是应答报文确认号为释放报文的序号加一,序号是原先规定的序号。这时服务器端进入关闭等待(CLOSE-WAIT)状态。上层应用会接到通知,表明不会有来自客户端的数据要处理了。关闭服务器读通道。
当客户端收到服务器端的应答报文,关闭客户端写通道(不再发送数据);这时客户端是半关闭状态,虽然结束了数据发送,其仍要接收处理来自服务器端的数据。客户端进入终止等待2(FIN-WAIT-2)状态。
第三次挥手:服务器发送完数据后进行被动的关闭操作,对称的有,服务器端发送释放报文FIN段置1,序号按原有规则设置,这里的确认段仍设置为1,确认号与之前发送的确认报文相同,服务器端进入(LAST-ASK)状态等待最后的确认报文。
第四次挥手:客户端接受到来自服务器端的FIN报文,就会关闭客户端读通道,并向服务器发送最后的应答报文,序号为FIN报文中的确认号,确认号为FIN报文中的序号加1。服务器进入了(TIME-WAIT)状态,等待两个MSL(Maximum Segment Lifetime,报文段最大生存时间)的时间后彻底结束连接。在这一状态下任何之前发送的迟到的报文都会被丢弃。
当服务器端接收到来自客户端的应答报文后,关闭服务器写通道,连接彻底关闭。
整个的流程中双方先关闭读通道(接收到FIN报文后),再关闭写通道(接收到FIN的应答报文后)。
2MSL
MSL是任何报文在网络上的存在的最长时间,超过这个时间报文将被丢弃。具体的实现是由各转发点根据报文时间戳进行处理的。
2MSL的必要性:保证最后一个应答报文可以顺利被对方接到,由于在这段时间所有之前发送的报文都将被丢弃,所以当进行一个新的连接的时候不会再有之前连接的报文。
状态转换
整个的TCP连接状态可以由以下的状态转换表示:
相关状态
- CLOSED:无连接状态,不建立连接
- LISTEN:处于监听状态,可以接受客户端的连接
- SYN-RECEIVED:接收到了请求连接的SYN报文
- SYN-SENT:发送SYN报文后进入该状态
- ESTABLISHED:表示TCP连接已经成功建立
- FIN-WAIT1:主动释放连接,发出FIN报文后。
- FIN-WAIT2:接收到对方的FIN确认报文(对方同意释放连接)。
- CLOSING:双方同时提出连接释放(在连发出FIN报文后没有收到应答报文,反而收到了对方的FIN)。
- TIMED-WAIT:收到了对方的FIN报文并发出了应答报文,等待全部的TCP报文传输完毕(2MSL等待)。
- CLOSE-WAIT:等待释放连接,当收到FIN报文并发送应答报文后,还需要查看自己这边有没有完成数据的发送,如果没有就在这一阶段完成剩余的数据传输。如果结束传输就发送FIN报文给对方,并结束这一状态。
- LAST-ASK:被动释放的一方发出FIN报文后等待对方的应答报文。
连接状态的转换
关于连接的状态有:LISTEN,SYN-RECEIVED,SYN-SENT,ESTABLISHED。
正常状态的TCP连接:
主动方:CLOSED->SYN-SENT->ESTABLISHED
被动方:CLOSED->LISTEN->SYN-RECEIVED->ESTABLISHED
双方同时建立连接:(四次握手)
连接方1:CLOSED->SYN-SENT->SYN-RECEIVED->ESTABLISHED
连接方2:CLOSED->SYN-SENT->SYN-RECEIVED->ESTABLISHED
被动方在连接未建立前提出连接请求:
被动方:CLOSED->LISTEN->SYN-SENT->SYN-RECEIVED->ESTABLISHED
被动方长时间不响应(超时):
主动方:CLOSED->SYN-SENT->CLOSED
被动方主动关闭:
被动方:CLOSED->LISTEN->CLOSED
主动方使用RST报文关闭异常连接:
被动方:CLOSED->LISTEN->SYN-RECEIVED->(出现异常主动方发出RST报文)->LISTEN
连接中途被动方主动释放:
被动方:CLOSED->LISTEN->SYN-RECEIVED(紧急情况,发出FIN报文请求释放)->FIN-WAIT1
释放状态的转换
关于释放的状态有:FIN-WAIT1,FIN-WAIT2,CLOSING,TIMED-WAIT,CLOSE-WAIT,LAST-ASK
正常状态的TCP释放:
主动方:ESTABLISHED->FIN-WAIT1->FIN-WAIT2->TIMED-WAIT->CLOSED
被动方:ESTABLISHED->CLOSE-WAIT->LAST-ASK->CLOSED
双方同时释放:
在接受到FIN的确认报文前接受到FIN报文则进入CLOSING状态,之后接受到确认报文后进入TIMED-WAIT状态。
释放方1:ESTABLISHED->FIN-WAIT1->CLOSING->TIMED-WAIT->CLOSED
释放方2:ESTABLISHED->FIN-WAIT1->CLOSING->TIMED-WAIT->CLOSED
被动释放的一方在收到FIN报文后无数据发送请求释放连接:
主动方:ESTABLISHED->FIN-WAIT1->TIMED-WAIT->CLOSED
被动方:ESTABLISHED->CLOSE-WAIT(时间极短几乎没有)->LAST-ASK->CLOSED