三次握手建立连接
TCP 发送数据之前要先建立连接(三次握手)
所谓三次握手(Three-way Handshake),是指建立一个TCP连接时,需要客户端和服务器总共发送3个包。
三次握手的目的是连接服务器指定端口,建立TCP连接,并同步连接双方的序列号和确认号并交换 TCP 窗口大小信息.在socket编程中,客户端执行connect()时。将触发三次握手。
两台主机,服务器(server)和客户机(client)
过程:
-
第一次握手: client将SYN位置1,随机产生一个值seq=x,并将该数据包发送给server,client进入SYN_SEND状态,等待server确认;
client告诉server两件事
①我想要和你通信
②你可以用哪个序列号作为起始数据段来回应我 -
第二次握手: server在收到包含SYN的报文之后,由于SYN位被值置1,知道client请求建立连接,server将SYN,ACK都置1,ack=x+1,随机产生一个值seq=y,并将该报文发送给client,server进入SYN_REVC状态;
server告诉client两件事:
①我已经收到你的请求了,你可以传输数据了;
②你要用哪种序列号作为起始数据段来回应我 -
第三次握手: client在收到server的SYN+ACK的报文之后,先检查ack是否为x+1,ACK是否为1,如果正确,就将ACK置为1,ack=y+1,并将报文发送给server,server会检查报文中的ACK是否为1,ack是否等于y+1,如果正确,client和server进入到ESTABLISHED状态,TCP连接建立。
3次握手的特点
①没有应用层的数据
②SYN这个标志位只有在TCP建产连接时才会被置1
③握手完成后SYN标志位被置0
三次握手过程中client和server的状态
发送方 | 接收方 | 报文 | 数据包 | client状态 | server状态 | 意义 |
---|---|---|---|---|---|---|
client | server | SYN确认报文 | SYN=1,seq=x | SYN_SEND | 客户端请求发起连接, 等待服务器确认请求 | |
server | client | SYN+ACK确认+同步报文 | SYN=1,ACK=1,seq=y,ack=x+1 | SYN_RECV | 服务器确认客户端的请求 | |
client | server | ACK确认报文 | ACK=1,ack=y+1,seq=x+1 | ESTABLISHED | ESTABLISHED | 客户端确认, 连接完成 |
四次挥手关闭连接
- 第一次挥手: client发送FIN报文(FIN=1,seq=u),表示client端发起中断连接请求,也就是发送FIN报文,发送完毕后client进入FIN_WAIT_1状态
- 第一次挥手: server收到FIN报文后,如果还有数据没有发送完成,则不必急着关闭Socket,可以继续发送数据。所以先回复ACK报文(ACK=1,seq=v,ack=u+1),发送完毕后server进入CLOSE_WAIT状态
- 第一次挥手: server端确定数据已发送完成,则向client端发送FIN报文(FIN=1,ACK=1,seq=w,ack=u+1),表示它要关闭TCP连接,发送完毕后进入LAST_ACK状态
- 第一次挥手: client收到FIN信号后,进入TIME_WAIT(倒计时)状态,接着发送一个ACK报文(FIN=1,ACK=1,seq=u+1,ack=w+1)给server。server收到该ACK后自行关闭,同时client超时后也关闭。连接关闭后,双方所有的资源都会被释放。
四次挥手过程中client和server的状态
发送方 | 接收方 | 报文 | 数据包 | client状态 | server状态 | 意义 |
---|---|---|---|---|---|---|
client | server | FIN | FIN=1,seq=u | FIN_WAIT_1 | 客户端 发起中断连接请求 | |
server | client | ACK | SYN=1,ACK=1,seq=v,ack=u+1 | FIN_WAIT_2 | CLOSE_WAIT | Client端就进入FIN_WAIT_2状态,继续等待Server端的FIN报文 |
server | client | FIN | FIN=1,ACK=1,seq=w,ack=u+1 | LAST_ACK | 服务器数据发完了,准备好关闭连接了 | |
client | server | ACK | FIN=1,ACK=1,seq=u+1,ack=w+1 | TIME_WAIT | 可以断开连接 |
为什么建立连接是三次握手,而关闭连接却是四次挥手呢?
因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。
其中ACK报文是用来应答的,SYN报文是用来同步的。
但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,”你发的FIN报文我收到了”。
只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。
故需要四步握手。
总结:因为server端的FIN和ACK是分开发送的。
三次握手和四次挥手的过程中,client和server的状态变化
client
server
状态 | 描述 |
---|---|
CLOSED | 关闭状态,没有连接活动或正在进行 |
LISTEN | 监听状态,服务器正在等待连接进入 |
SYN RCVD | 收到一个连接请求,尚未确认 |
SYN SENT | 已经发出连接请求,等待确认 |
ESTABLISHED | 连接建立,正常数据传输状态 |
FIN WAIT 1 | (主动关闭)已经发送关闭请求,等待确认 |
FIN WAIT 2 | (主动关闭)收到对方关闭确认,等待对方关闭请求 |
TIMED WAIT | 完成双向关闭,等待所有分组死掉 |
CLOSING | 双方同时尝试关闭,等待对方确认 |
CLOSE WAIT | (被动关闭)收到对方关闭请求,已经确认 |
LAST ACK | (被动关闭)等待最后一个关闭确认,并等待所有分组死掉 |