TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。TCP的主要目标是提供一种可靠的、有序的和错误校验的数据传输方式,以确保数据在网络中的可靠传输。
主要特点:
面向连接:在传输数据之前,必须先建立TCP连接。连接是可靠的服务,具有固定的连接端点。
可靠传输:TCP提供了数据传输的确认和重传机制,以确保数据的顺序和完整性。如果数据在传输过程中丢失或损坏,TCP会重新发送数据,以确保接收端能够正确地接收到数据。
流量控制:TCP提供了一种机制,用于控制发送方发送数据的速度,以防止接收方来不及接收数据而造成数据丢失。
拥塞控制:当网络拥塞时,TCP会降低发送数据的速度,以减少网络拥塞。TCP使用一系列算法来检测和防止网络拥塞。
字节流:TCP将应用程序中的数据作为字节流发送,没有消息边界的概念。这意味着发送端可以连续发送数据,而接收端必须按顺序接收字节流并重新组合成有意义的数据。
TCP广泛应用于互联网协议(IP)网络中,是互联网协议(IP)的重要组成部分。许多应用程序和协议都使用TCP作为其传输层协议,例如HTTP、FTP、SMTP和许多其他协议。
在发送数据前,通信双方必须在彼此间建立一条连接。所谓的“连接”,其实是客户端和服务端保存的一份关于对方的信息,如ip地址、端口号等。TCP可以看成是一种字节流,它会处理IP层或以下的层的丢包、重复以及错误问题。在连接的建立过程中,双方需要交换一些连接的参数。这些参数可以放在TCP头部。一个TCP连接由一个4元组构成,分别是两个IP地址和两个端口号。一个TCP连接通常分为三个阶段:连接、数据传输、退出(关闭)。通过三次握手建立一个链接,通过四次挥手来关闭一个连接。当一个连接被建立或被终止时,交换的报文段只包含TCP头部,而没有数据。
TCP报文头部结构
源端口和目的端口:用于标识发送和接收数据的进程。
序号:seq序号,占32位,用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记,以便在接收端重新排序并组装数据。
确认号:ack序号,占32位,只有ACK标志位为1时,确认序号字段才有效,ack=seq+1,用于确认接收到的数据,并告诉发送端下一个期望接收的字节号。
头部长度:指示TCP头部的大小(以32位字为单位)。
标志位:URG、ACK、PSH、RST、SYN和FIN等标志,用于指示TCP的状态和操作。标志位具体含义如下:
ACK:确认序号有效。
FIN:释放一个连接。
PSH:接收方应该尽快将这个报文交给应用层。
RST:重置连接。SYN:发起一个新连接。
URG:紧急指针(urgent pointer)有效。
窗口大小:用于流量控制,指示接收端可接收的最大数据量。
校验和:用于检测数据在传输过程中的错误。
紧急指针:用于标识紧急数据的字节号。
TCP选项:可变长的可选信息,例如最大段大小、时间戳等。
三次握手
TCP的三次握手过程是建立TCP连接的过程,目的是为了初始化通信双方sequence number的初始值。
第一次握手:客户端发送SYN包(SYN=1)到服务器,并进入SYN_SEND状态,等待服务器确认。客户端要向服务端发起连接请求,首先客户端随机生成一个起始序列号ISN(比如是100),那客户端向服务端发送的报文段包含SYN标志位(也就是SYN=1),序列号seq=100。
第二次握手:服务器收到SYN包,必须确认客户端的SYN(ACK=1,ack=x+1),同时自己也发送一个SYN包(SYN=1,seq=y)给客户端,即SYN+ACK包,此时服务器进入SYN_RECV状态。服务端收到客户端发过来的报文后,发现SYN=1,知道这是一个连接请求,于是将客户端的起始序列号100存起来,并且随机生成一个服务端的起始序列号(比如是300)。然后给客户端回复一段报文,回复报文包含SYN和ACK标志(也就是SYN=1,ACK=1)、序列号seq=300、确认号ack=101(客户端发过来的序列号+1)。
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ACK=1,ack=y+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。客户端收到服务端的回复后发现ACK=1并且ack=101,于是知道服务端已经收到了序列号为100的那段报文;同时发现SYN=1,知道了服务端同意了这次连接,于是就将服务端的序列号300给存下来。然后客户端再回复一段报文给服务端,报文包含ACK标志位(ACK=1)、ack=301(服务端序列号+1)、seq=101(第一次握手时发送报文是占据一个序列号的,所以这次seq就从101开始,需要注意的是不携带数据的ACK报文是不占据序列号的,所以后面第一次正式发送数据时seq还是101)。当服务端收到报文后发现ACK=1并且ack=301,就知道客户端收到序列号为300的报文了,就这样客户端和服务端通过TCP建立了连接。
四次挥手
四次挥手过程是用于正常关闭TCP连接的过程。
比如客户端初始化的序列号ISA=100,服务端初始化的序列号ISA=300。TCP连接成功后客户端总共发送了1000个字节的数据,服务端在客户端发FIN报文前总共回复了2000个字节的数据。
第一次挥手:客户端发送一个FIN包,表示想要关闭TCP连接。客户端进入FIN_WAIT_1状态,等待服务器确认。当客户端的数据都传输完成后,客户端向服务端发出连接释放报文(当然数据没发完时也可以发送连接释放报文并停止发送数据),释放连接报文包含FIN标志位(FIN=1)、序列号seq=1101(100+1+1000,其中的1是建立连接时占的一个序列号)。需要注意的是客户端发出FIN报文段后只是不能发数据了,但是还可以正常收数据;另外FIN报文段即使不携带数据也要占据一个序列号。
第二次挥手:服务器收到FIN包后,发送一个ACK包给客户端,确认客户端的请求,服务器进入CLOSE_WAIT状态。服务端收到客户端发的FIN报文后给客户端回复确认报文,确认报文包含ACK标志位(ACK=1)、确认号ack=1102(客户端FIN报文序列号1101+1)、序列号seq=2300(300+2000)。此时服务端处于关闭等待状态,而不是立马给客户端发FIN报文,这个状态还要持续一段时间,因为服务端可能还有数据没发完。
第三次挥手:服务器发送一个FIN包给客户端,表示自己想要关闭连接。服务器进入LAST_ACK状态,等待客户端的确认。服务端将最后数据(比如50个字节)发送完毕后就向客户端发出连接释放报文,报文包含FIN和ACK标志位(FIN=1,ACK=1)、确认号和第二次挥手一样ack=1102、序列号seq=2350(2300+50)。
第四次挥手:客户端收到服务器的FIN包后,发送一个ACK包给服务器,确认服务器的请求。客户端进入TIME_WAIT状态,等待足够长的时间以确保服务器收到了自己的确认。然后客户端进入CLOSED状态,关闭连接。服务器收到ACK包后,进入CLOSED状态,关闭连接。客户端收到服务端发的FIN报文后,向服务端发出确认报文,确认报文包含ACK标志位(ACK=1)、确认号ack=2351、序列号seq=1102。注意客户端发出确认报文后不是立马释放TCP连接,而是要经过2MSL(最长报文段寿命的2倍时长)后才释放TCP连接。而服务端一旦收到客户端发出的确认报文就会立马释放TCP连接,所以服务端结束TCP连接的时间要比客户端早一些。