本文共 3144 字,大约阅读时间需要 10 分钟。
TCP建立连接需要进行“三次握手”:
TCP三次握手过程描述如下:
客户端发送连接请求报文:SYN标志位为1,ACK标志位为0,序列号seq为x。然后客户端进入SYN_SENT状态,等待服务器的确认响应;
服务器收到客户端的连接请求,对这个SYN报文段进行确认,发送:SYN标志位为1,ACK标志位为1,序列号seq为y,确认序列号ack为x+1。此时服务器进入SYN_RCVD状态;
客户端收到服务器的SYN+ACK报文段,确认ACK后,发送:SYN标志位为0,ACK标志位为1,序列号seq为x+1,确认序列号ack为y+1。发送完成后,客户端和服务器端都进入ESTABLISHED状态,完成TCP三次握手。
TCP断开连接需要进行“四次挥手”:
TCP四次挥手过程描述如下:
主机1(可以使客户端,也可以是服务器端)发送:FIN标志位为1,ACK标志位为0,序列号seq为u。此时,主机1进入FIN_WAIT_1状态。
主机2收到了主机1发送的FIN报文段,向主机1回一个ACK报文段:FIN标志位为1,ACK标志位为1,序列号seq为v,确认序列号ack为u+1。主机1进入FIN_WAIT_2状态;主机2进入CLOSE_WAIT状态。
主机2向主机1发送FIN报文段:FIN标志位为1,ACK标志位为1,序列号seq为w,确认序列号ack为u+1。请求关闭连接,同时主机2进入LAST_ACK状态。
主机1收到主机2发送的FIN报文段,向主机2发送ACK报文段:FIN标志位为1,ACK标志位为1,序列号seq为u+1,确认序列号ack为w+1。,然后主机1进入TIME_WAIT状态;主机2收到主机1的ACK报文段以后,就关闭连接;此时,主机1等待2MSL后依然没有收到回复,则证明Server端已正常关闭,那么,主机1也可以关闭连接了。
(1)全双工:
意味着,TCP的收发是可以同时进行的。也就是说收的时候可以发,发的时候也可以收,两者互不冲突。(2)字节:
意味着,无论物理层或链路层收到的数据是否为一个个bit的数据,在TCP层一定是一个个字节。(3)流:
意味着,socket的数据无头无尾,就像流水一样,如果从中间任意位置起,你无法知道一个消息包确切的开始或结束位置,除非从TCP的头开始算起。也就是意味着,我们在应用层编程时,必须定义一个应用层的包头,从收到的第一个字节开始,通过该包头能确定一个包的长度,然后根据包的长度,确定一个个包的起止位置。这也就是我们看到所有的TCP的socket编程中,都需要定义一个包头的原因。因为TCP是“全双工通信”。
前提1:TCP协议要保证双方可以建立可靠的通信。 即 发送端、接收端要确认自己发送的信息对方能接收到,对方发送的信息自己能接收到。(必须确认收、发正常) 前提2:在前提1的情况下“握手”的次数越少越好。(1)第一次握手
发送端向接受端发送一个SYN包。发送端:无法确认自己发送的信息对方是否收到。
(2)第二次握手
接收端收到SYN包之后,接收端回一个ACK包。发送端:可以确定自己发送的信息能被对方收到,也能确定对方发的信息自己能收到。
接收端:只能确定对方发的包自己能收到, 无法确定自己发的包对方能收到。(3)第三次握手
发送端接收到SYN,之后再发一个ACK。接收端:能够确定字节发送的消息,发送端能够收到。
主要是为了防止发送方已失效的连接请求报文段突然又传到了B,因而产生错误。假定出现一种异常情况,即A发出的第一个连接请求报文段并没有丢失,而是在某些网络结 点长时间滞留了,一直延迟到连接释放以后的某个时间才到达B,本来这是一个早已失效的报文段。但B收到此失效的连接请求报文段后,就误认为是A又发出一次 新的连接请求,于是就向A发出确认报文段,同意建立连接。假定不采用三次握手,那么只要B发出确认,新的连接就建立了,这样一直等待A发来数据,B的许多 资源就这样白白浪费了。
原因有二:
(1)保证TCP协议的全双工连接能够可靠关闭。 (2)保证这次连接的重复数据段从网络中消失。先说第一点,如果Client直接CLOSED了,那么由于IP协议的不可靠性或者是其它网络原因,导致Server没有收到Client最后回复的ACK。那么Server就会在超时之后继续发送FIN,此时由于Client已经CLOSED了,就找不到与重发的FIN对应的连接,最后Server就会收到RST而不是ACK,Server就会以为是连接错误把问题报告给高层。这样的情况虽然不会造成数据丢失,但是却导致TCP协议不符合可靠连接的要求。所以,Client不是直接进入CLOSED,而是要保持TIME_WAIT,当再次收到FIN的时候,能够保证对方收到ACK,最后正确的关闭连接。
再说第二点,如果Client直接CLOSED,然后又再向Server发起一个新连接,我们不能保证这个新连接与刚关闭的连接的端口号是不同的。也就是说有可能新连接和老连接的端口号是相同的。一般来说不会发生什么问题,但是还是有特殊情况出现:假设新连接和已经关闭的老连接端口号是一样的,如果前一次连接的某些数据仍然滞留在网络中,这些延迟数据在建立新连接之后才到达Server,由于新连接和老连接的端口号是一样的,又因为TCP协议判断不同连接的依据是socket pair,于是,TCP协议就认为那个延迟的数据是属于新连接的,这样就和真正的新连接的数据包发生混淆了。所以TCP连接还要在TIME_WAIT状态等待2倍MSL,这样可以保证本次连接的所有数据都从网络中消失。
MSL是Maximum Segment Lifetime英文的缩写,中文可以译为“报文最大生存时间”,他是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。因为tcp报文(segment)是ip数据报(datagram)的数据部分,具体称谓请参见《数据在网络各层中的称呼》一文,而ip头中有一个TTL域,TTL是time to live的缩写,中文可以译为“生存时间”,这个生存时间是由源主机设置初始值但不是存的具体时间,而是存储了一个ip数据报可以经过的最大路由数,每经过一个处理他的路由器此值就减1,当此值为0则数据报将被丢弃,同时发送ICMP报文通知源主机。RFC 793中规定MSL为2分钟,实际应用中常用的是30秒,1分钟和2分钟等。
2MSL即两倍的MSL,TCP的TIME_WAIT状态也称为2MSL等待状态,当TCP的一端发起主动关闭,在发出最后一个ACK包后,即第3次握手完成后发送了第四次握手的ACK包后就进入了TIME_WAIT状态,必须在此状态上停留两倍的MSL时间,等待2MSL时间主要目的是怕最后一个ACK包对方没收到,那么对方在超时后将重发第三次握手的FIN包,主动关闭端接到重发的FIN包后可以再发一个ACK应答包。在TIME_WAIT状态时两端的端口不能使用,要等到2MSL时间结束才可继续使用。当连接处于2MSL等待阶段时任何迟到的报文段都将被丢弃。不过在实际应用中可以通过设置SO_REUSEADDR选项达到不必等待2MSL时间结束再使用此端口。
TTL与MSL是有关系的但不是简单的相等的关系,MSL要大于等于TTL。