TCP中三次握手建立和四次握手释放以及相关问题
本文基于个人所学和网上博文所整理,若有不妥处,欢迎留言指出
TCP连接过程中标志位的意义:
字符缩写 | 描述 |
SYN | 同步序号,表示此报文是一个连接请求或连接接受报文 |
ACK | 确认位,对接收到的报文的确认 |
FIN | 终止位,表示发送方完成数据发送,用来释放一个连接 |
RST | 复位连接,表示TCP连接中出现严重错误 |
PSH | 推送位,尽可能快递将数据送往接受进程 |
一、三次握手建立
1、三次握手建立连接详解
TCP建立连接要进行“三次握手”,即交换三个分组。大致流程如下:
(1)客户端向服务器发送一个SYN J,并进入SYN_SEND状态,等待服务器确认;;
(2)服务器向客户端响应一个SYN K,并对SYN J进行确认ACK J+1,此时服务器 进入SYN_RECV状态;
(3)客户端再想服务器发一个确认ACK K+1,客户端和服务器进入 ESTABLISHED状态,完成三次握手。。
三次握手发生在socket的那几个函数:
从图中可以看出,当客户端调用connect时,触发了连接请求,向服务器发送了SYN J包,这时connect进入阻塞状态;服务器监听到连接请求,即收到SYN J包,调用accept函数接收请求向客户端发送SYN K ,ACK J+1,这时accept进入阻塞状态;客户端收到服务器的SYN K ,ACK J+1之后,这时connect返回,并对SYN K进行确认;服务器收到ACK K+1时,accept返回,至此三次握手完毕,连接建立。
总结:客户的的connect在第三次握手的第二次返回,二服务器的accept在三次握手的第三次返回。
2、若是出现丢包的情况,会如何?(来自:TCP 为什么是三次握手,为什么不是两次或四次?车小胖的回答)(A对应客户端,B对应服务器)
(1)第一个包,即A发给B的SYN 中途被丢,没有到达B
A会周期性超时重传,直到收到B的确认;
(2)第二个包,即B发给A的SYN +ACK 中途被丢,没有到达A
B会周期性超时重传,直到收到A的确认;
(3)第三个包,即A发给B的ACK中途丢失,没有到达B
A发完ACK,单方面认为TCP为Established状态,而B显然认为TCP为Active状态:
- 假定此时双方都没有数据发送,B会周期性超时重传,直到收到A的确认,收到之后B的TCP 连接也为 Established状态,双向可以发包。
- 假定此时A有数据发送,B收到A的 Data + ACK,自然会切换为established 状态,并接受A的 Data。
- 假定B有数据发送,数据发送不了,会一直周期性超时重传SYN + ACK,直到收到A的确认才可以发送数据。
3、TCP 为什么是三次握手,为什么不是两次或四次?
三次握手的目的是什么?以下引用知乎作者郭无心的回答:
在谢希仁著《计算机网络》第四版中讲“三次握手”的目的是“为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误”。已失效的连接请求报文段”的产生在这样一种情况下:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。”
另外,三次握手的最主要目的是保证连接是双工的,可靠更多的是通过重传机制来保证的。我们可以通过打招呼的例子来说明。
二、四次挥手释放
1、四次挥手释放过程详解
由于TCP连接时全双工的,因此,每个方向都必须要单独进行关闭,这一原则是当一方完成数据发送任务后,发送一个FIN来终止这一方向的连接,收到一个FIN只是意味着这一方向上没有数据流动了,即不会再收到数据了,但是在这个TCP连接上仍然能够发送数据,直到这一方向也发送了FIN。首先进行关闭的一方将执行主动关闭,而另一方则执行被动关闭,上图描述的即是如此。
(1)第一次挥手:Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。
(2)第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server进入CLOSE_WAIT状态。
(3)第三次挥手:Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态。
(4)第四次挥手:Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,Server进入CLOSED状态,完成四次挥手。
这里引用whuslei的博文TCP协议中的三次握手和四次挥手(图解)中更为生动的解释:
假设Client端发起中断连接请求,也就是发送FIN报文。Server端接到FIN报文后,意思是说"我Client端没有数据要发给你了",但是如果你还有数据没有发送完成,则不必急着关闭Socket,可以继续发送数据。所以你先发送ACK,"告诉Client端,你的请求我收到了,但是我还没准备好,请继续你等我的消息"。这个时候Client端就进入FIN_WAIT状态,继续等待Server端的FIN报文。当Server端确定数据已发送完成,则向Client端发送FIN报文,"告诉Client端,好了,我这边数据发完了,准备好关闭连接了"。Client端收到FIN报文后,"就知道可以关闭连接了,但是他还是不相信网络,怕Server端不知道要关闭,所以发送ACK后进入TIME_WAIT状态,如果Server端没有收到ACK则可以重传。“,Server端收到ACK后,"就知道可以断开连接了"。Client端等待了2MSL后依然没有收到回复,则证明Server端已正常关闭,那好,我Client端也可以关闭连接了。Ok,TCP连接就这样关闭了!
2、为什么连接的时候是三次握手,关闭的时候却是四次挥手?
答:因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了"。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。
3、为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?
答:主要是防止最后一个ACK丢失!!!虽然按道理,四个报文都发送完毕,我们可以直接进入CLOSE状态了,但是我们必须假象网络是不可靠的,有可以最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。Server如果没有收到ACK,将不断重复发送FIN片段。所以Client不能立即关闭,它必须确认Server接收到了该ACK。Client会在发送出ACK之后进入到TIME_WAIT状态。Client会设置一个计时器,等待2MSL的时间。如果在该时间内再次收到FIN,那么Client会重发ACK并再次等待2MSL。所谓的2MSL是两倍的MSL(Maximum Segment Lifetime)。MSL指一个片段在网络中最大的存活时间,2MSL就是一个发送和一个回复所需的最大时间。如果直到2MSL,Client都没有再次收到FIN,那么Client推断ACK已经被成功接收,则结束TCP连接。另外在等待2MLS的时间中,五元组(源、目IP和端口号以及协议号)都不能用,是为了防止网络中迟来数据。
Ref:
http://www.cnblogs.com/huhuuu/p/3572485.html
http://blog.csdn.net/whuslei/article/details/6667471