序
这是 TCP 协议系列文章的第二篇,上一篇文章中对 TCP 协议进行了简单介绍,由介绍可知,建立在 TCP 协议上的应用需要先建立一个TCP 连接,才能收发数据,本博文就主要介绍 TCP 连接的建立与终止的过程,及在这个过程中需要注意的问题。
3 次握手建立 TCP 连接
1、 第一次握手:客户端发送 SYN 包( SYN = 1 && 序号 = x )到服务器,并进入 SYN_SEND 状态,等待服务器确认;
2、 第二次握手:服务器收到 SYN 包,必须确认客户的 SYN(ACK = 1 && ack = x+1),同时自己也发送一个SYN包(SYN = 1 && 序号 = y),即 SYN + ACK 包,此时服务器进入SYN_RECV 状态;
3、第三次握手:客户端收到服务器的 SYN+ACK 包,向服务器发送确认包 ACK (ACK = 1 && ack=y+1),此包发送完毕,客户端进入 ESTABLISHED 状态,服务端收到客户端的确认包后,也进入 ESTABLISHED 状态,完成三次握手。
** 注意 **:握手过程中传送的包里不包含数据,三次握手完毕后,客户端与服务器才正式开始传送数据。理想状态下,TCP 连接一旦建立,在通信双方中的任何一方主动关闭连接之前,TCP 连接都将被一直保持下去。
3 次握手建立 TCP 连接4 次挥手断开 TCP 连接
与建立连接的 “三次握手” 类似,断开一个 TCP 连接则需要 “四次挥手”。
1、 第一次挥手:主动关闭方发送一个 FIN(进入FIN_WAIT_1 状态),用来关闭主动方到被动关闭方的数据传送,也就是主动关闭方告诉被动关闭方:我已经不会再给你发数据了(当然,在 FIN 包之前发送出去的数据,如果没有收到对应的 ACK 确认报文,主动关闭方依然会重发这些数据),但是,此时主动关闭方还可以接受数据。
2、 第二次挥手:被动关闭方收到 FIN 包后,发送一个 ACK 给对方(进入CLOSE_WAIT状态),确认序号为收到序号+ 1(与 SYN 相同,一个 FIN 占用一个序号)。主动关闭方收到该包后进入 FIN_WAIT_2 状态。
3、 第三次挥手:被动关闭方发送一个 FIN(进入 LAST_ACK状态),用来关闭被动关闭方到主动关闭方的数据传送,也就是告诉主动关闭方,我的数据也发送完了,不会再给你发数据了。
4、 第四次挥手:主动关闭方收到 FIN 后,发送一个 ACK 给被动关闭方(进入 TIME_WAIT 状态),确认序号为收到序号 + 1。
5、 被动关闭方收到确认包后,进入 CLOSED 状态,主动关闭方在发送完确认包并经过 2 MSL 时间后,进入 CLOSED 状态。至此,4 次挥手过程结束,TCP 连接终止。
相关问题
** 为什么需要通过 3 次握手建立 TCP 连接? **
主要是为了防止两次握手情况下已失效的连接请求报文段突然又传送到服务端,而产生的错误。举例如下:客户 A 向服务器 B 发出 TCP 连接请求,第一个连接请求报文在网络的某个节点长时间滞留,A 超时后认为报文丢失,于是再重传一次连接请求,B 收到后建立连接。数据传输完毕后双方断开连接。而此时,前一个滞留在网络中的连接请求到达了服务端B,而 B 认为 A 又发来连接请求,若采用的是“两次握手”,则这种情况下 B 认为传输连接已经建立,并一直等待 A 传输数据,而 A 此时并无连接请求,因此不予理睬,这样就造成了 B 的资源白白浪费了;但此时若是使用“三次握手”,则 B 向 A 返回确认报文段,由于是一个失效的请求,因此 A 不予理睬,建立连接失败。第三次握手的作用:防止已失效的连接请求报文段突然又传送到了服务器。
** 关闭 TCP 连接一定需要 4 次挥手吗? **
不一定,4 次挥手关闭 TCP 连接是最安全的做法。但在有些时候,我们不喜欢 TIME_WAIT 状态(如当 MSL 数值设置过大导致服务器端有太多 TIME_WAIT 状态的 TCP连接,减少这些条目数可以更快地关闭连接,为新连接释放更多资源),这时我们可以通过设置 SOCKET 变量的 SO_LINGER 标志来避免 SOCKET 在 close() 之后进入 TIME_WAIT状态,这时将通过发送 RST 强制终止 TCP 连接(取代正常的 TCP 四次握手的终止方式)。但这并不是一个很好的主意,TIME_WAIT 对于我们来说往往是有利的。
** TIME_WAIT 状态的作用 **
1、为了保证客户端发送的最后一个 ACK 报文段能够达到服务器。 这个 ACK 报文段可能丢失,因而使处在 LAST_ACK 状态的服务器收不到确认。这样的话, 服务器会超时重传FIN+ACK 报文段,客户端就能在2MSL时间内收到这个重传的 FIN+ACK 报文段,接着客户端重传一次确认,重启计时器。最后,客户端和服务器都正常进入到 CLOSED 状态。如果客户端在 TIME_WAIT 状态不等待一段时间,而是在发送完 ACK 报文后立即释放连接,那么就无法收到服务器重传的 FIN+ACK 报文段,因而也不会再发送一次确认报文。这样,服务器就无法按照正常步骤进入 CLOSED 状态。
2、防止已失效的连接请求报文段出现在本连接中。客户端在发送完最后一个 ACK 确认报文段后,再经过时间 2MSL,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样就可以使下一个新的连接中不会出现这种旧的连接请求报文段。
** 注意 **:服务器结束 TCP 连接的时间要比客户端早一些,因为客户机(最先提出 close 请求的一端)最后要等待 2MSL 后才可以进入 CLOSED 状态。
网友评论