TCP全名Tranmission Control Protocol,是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 793定义。TCP主要解决了UDP通信数据传输不可靠问题,即建立在不可靠通讯的基础之上,并辅之以自动窗口大小、重传、拥塞控制等机制。建立连接和断开连接,本质上是TCP的状态位不停变化,在不同的连接状态下进行数据操作。
其中,建立连接和断开连接是资源能正确使用和释放的前提,分为三次握手和四次分手,那么为什么是三次和四次这样的一种形式,而不是其他形式?本文将针对此问题,进行详细分析。下图来自WikiPedia TCP
TCP建立连接
- 服务器处于监听状态,客户端发起连接请求:SYN=x
- 服务端确认到SYN后,返回ACK=x+1,并向客户端发起SYN=y请求
- 客户端收到ACK和SYN,并向服务端返回ACK=y+1
- 连接建立
那为什么是三次握手呢,而不是四次或者两次,甚至更多?
【问题1】为什么不是两次?
TCP是建立在不可靠的数据通讯上,即面向无连接的UDP,若不进行互相确认就进行通讯,双方可能都收不到,直接丢包。平时打电话的时候就是很好的例子,只有双方都确认能听到声音了,才进行下一步的交谈。
【问题2】为什么不是四次或更多次?
假设确实是四次或更多次,从定义上说,主要在于对ACK包的确认,即需要确认对方收到了ACK包。在第三步后,即客户端向服务端发送ACK=y+1后,服务端为了表明收到了ACK,再向客户端返回ACK=y+2,客户端收到ACK,再向服务端返回ACK=y+3,...以此类推,为了ACK而ACK,无穷无尽,这样永远也建立不了连接。
TCP断开连接
- TCP在已经建立连接的基础上,客户端发起FIN=x请求;
- 服务端收到FIN=x,返回ACK=x+1,并使服务端进入不接收数据的状态;
- 等待服务端发送完所有数据后,服务端发送FIN=y;
- 客户端接收到FIN包,返回ACK=y+1;
- 断开连接。
【问题1】为什么连接的时候是三次握手,关闭的时候却是四次握手?
因为当服务端收到客户端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当服务端收到FIN报文时,因数据没发送完,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉客户端,"你发的FIN报文我收到了"。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送,故需要四步握手。
在做了斯坦福CS144课程作业有后感,这是另一种解释:TCP通讯为全双工通信,即能同时进行接收和发送,数据的流通方式主要通过操作系统API,即从网卡中获取数据或发送数据,发送和接收分为两条流水线。如下图所示,一方发送数据,另一方接收数据。
数据在网络中的展现像流水线一样,只要有数据,延绵不绝。当服务器还有数据发送,而此时客户端发起FIN请求,说明客户端不发数据了,服务器收到后将接收数据的流水线关闭,但因服务器还要发送数据,不能关闭服务器的发送流水线,需等都发完后再关闭。状态变更未下图所示。
等服务端发完所有数据,由服务端发送FIN后, 两者的连接才会进入新的状态,最后进入关闭状态。
【问题2】若运行过程中,有一方突然长时间掉线,如何处理?
和断开连接没关系,属于TCP机制的一部分。因TCP超过一定重传次数后,TCP状态直接至为RST,此时处于连接重置状态,数据接收和发送都不可用。
Wireshark关于TCP建立和断开实例
这里以向腾讯IP发起TCP连接为例,IP和端口:125.39.52.26:443。
1. 建立连接的数据包样式
过程1:建立TCP请求,发起SYN
过程2:服务端返回SYN+ACK
过程3:客户端返回ACK