TCP连接

228 阅读3分钟

序列号seq:占4个字节,用来标记数据段的顺序;

确认号ack:占4个字节,期待收到对方下一个报文段的第一个数据字节的序号;

确认ACK:占1位,仅当ACK=1时,确认号字段才有效。ACK=0时,确认号无效

同步SYN:连接建立时用于同步序号。

三次握手

第一次:客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;

第二次握手:服务器接收到 syn包,必须确认客户的 SYN(ack=j+1)(ack:确认字符,表示发来的数据已确认接收无误),同时自己也发送一个 syn包(seq=k),既 SYN+ACK 包,此时服务器进入SYN_RECV(发送了ACK)状态。

第三次握手:客户端收到服务端发送的 SYN+ACK 包,向服务端发送确认包 ACK(ack=k+1),包发送完毕,客户端与服务器进入 ESTABLISHED(TCP连接成功)状态,完成三次握手。

ps:TCP还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。

四次挥手

第一次挥手:客户端进程发出连接释放报文,并且停止发送数据。释放数据报文首部FIN=1,其序列号为seq=u(等于前面的数据的最后一个字节的序号加1),此时,客户端进入FIN-WAIT-1(终止等待1)状态。 TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。

第二次挥手:服务器收到FIN=1,发出确认报文,ACK=1,ack=u+1,并且带上自己的序列号seq=v,服务端进入了CLOSE-WAIT状态。

第三次挥手:服务器关闭客户端连接,发送一个 FIN+ACK+SEQ 给客户端。进入 LAST_ACK 状态。

ps:为什么先发送ACK时不发送FIN

当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。ACK报文用来应答,SYN报文用来同步。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,发送的的FIN报文收到了。只有等到Server端所有的报文都发送完了,服务端才能发送FIN报文到客户端,因此不能一起发送。

第四次挥手:客户端发送 ACK(ACK=SQE序号+1)报文确认,客户端进入 TIME_WAIT 状态,服务端收到 ACK 进入 CLOSE状态。

ps:TIME_WAIT状态就是用来重发可能丢失的ACK报文。Client发送出最后的ACK回复,但该ACK可能丢失。Server如果没有收到ACK,将不断重复发送FIN片段。所以Client不能立即关闭,它必须确认Server接收到了该ACK。Client会在发送出ACK之后进入到TIME_WAIT状态。Client会设置一个计时器,等待2MSL的时间。如果在该时间内再次收到FIN,那么Client会重发ACK并再次等待2MSL。(MSL指一个片段在网络中最大的存活时间)果直到2MSL,Client都没有再次收到FIN,那么Client推断ACK已经被成功接收,则结束TCP连接。