TCP 三次握手/四次挥手
TCP 在传输之前会进行三次沟通,一般称为“三次握手”,传完数据断开的时候要进行四次沟通,一般称为“四次挥手”。
1.TCP3次握手
名词解释:
-
seq :Sequence Number 序列号,占4个字节,用来标记数据段的顺序,本地随机产生
-
ack:ACK:Acknowledgment Number 确认号,占4个字节,ack=seq+1
-
ACK:占1位,仅当ACK=1时,确认号字段才有效。ACK=0时,确认号无效
-
SYN:连接建立时用于同步序号
-
终止FIN:用来释放一个连接。FIN=1表示:此报文段的发送方的数据已经发送完毕,并要求释放运输连接
PS:ACK、SYN和FIN这些大写的单词表示标志位,其值要么是1,要么是0;ack、seq小写的单词表示序号。
第一次握手:
- 建立连接。客户端发送
- 客户端发送报文 SYN=1,,序列号Seq 假设为x ( 一般 为1 );
- 客户端进入同步已发送(SYN_SEND)状态,等待服务器的确认;
建立连接时,客户端发送syn包(syn=x)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)
第二次握手:
- 服务端收到客户端的SYN报文段,需对这个报文段进行确认 , 设置ack= x+1 (其实是seq值+1 );
- 同时组织 SYN请求信息,将SYN=1,ACK=1, 随机生成Seq假设为y;
- 将上述所有信息放到一个报文段(即SYN+ACK报文段)中,发送给客户端,
- 此时服务器进入同步接收状态(SYN_RECV );
第三次握手:
- 客户端收到服务器的SYN+ACK报文段。
- 检查 ack number 是否正确,
- 然后将ACK=1 , seq=x+1, ack=y+1,向服务器发送ACK报文段,
- 报文段发送完毕以后,客户端和服务器端都进入ESTABLISHED,已建立连接状态,完成TCP三次握手。
2.TCP 4次挥手
第一次挥手
- 客户端发送报文,FIN=1,seq=u,此时进入FIN-WAIT-1状态,
- 即半关闭阶段。并且停止在客户端到服务器端方向上发送数据,但是客户端仍然能接收从服务器端传输过来的数据。
第二次挥手
- 服务端收到报文,
- 服务端进入关闭等待状态(CLOSE_WATI),返回一个报文,ACK=1,ack=u+1,seq=v。
- 客户端收到这个报文之后,直接进入FIN-WAIT-2状态,此时客户端到服务端的连接就释放了。
第三次挥手
- 服务端发送连接释放报文,FIN=1,ACK=1 , ack=u+1,seq=w,
- 服务端进入最后确认状态(LAST-ACK),
第四次挥手
- 客户端收到连接释放报文之后,发应答报文,ACK=1,ack=w+1,seq=u+1,
- 进入时间等待状态(TIME_WAIT),等待2MSL(即两倍的MSL)后客户端进入关闭状态(CLOSED),
- 服务端收到报文之后就进入CLOSED状态。
3.为什么不能2次握手而是要三次握手?
- TCP是一个双向通信协议,通信双方都有能力发送信息,并接收响应。
- 为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。
具体例子:“已失效的连接请求报文段”的产生在这样一种情况下:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。
4.为什么要四次挥手?
TCP协议是一种面向连接的、可靠的、基于字节流的运输层通信协议。TCP是全双工模式,这就意味着,当主机1发出FIN报文段时,只是表示主机1已经没有数据要发送了,主机1告诉主机2,它的数据已经全部发送完毕了;但是,这个时候主机1还是可以接受来自主机2的数据;当主机2返回ACK报文段时,表示它已经知道主机1没有数据发送了,但是主机2还是可以发送数据到主机1的;当主机2也发送了FIN报文段时,这个时候就表示主机2也没有数据要发送了,就会告诉主机1,我也没有数据要发送了,之后彼此就会愉快的中断这次TCP连接。
5.为什么三次握手确要四次挥手?
TCP协议是一种面向连接的、可靠的、基于字节流的运输层通信协议。TCP是全双工模式,
当客户端发起主动关闭请求FIN 报文,仅仅表示客户端没有数据发送了,但是这个时候还可以接收来自服务端的数据。
需要等待服务端确认向客户端发送数据也完成,才可以关闭。
6.为什么客户端最后还要等待2MSL?
• 客户端需要保证最后一次发送的ACK报文到服务器,如果服务器未收到,可以请求客户端重发,这样客户端还有时间再发,重启2MSL计时。
7.TCP首部的组成
struct tcp_hdr {
PACK_STRUCT_FIELD(u16_t src); /* 源端口 */
PACK_STRUCT_FIELD(u16_t dest); /* 目的端口 */
PACK_STRUCT_FIELD(u32_t seqno); /* 序号 */
PACK_STRUCT_FIELD(u32_t ackno); /* 确认序号 */
PACK_STRUCT_FIELD(u16_t _hdrlen_rsvd_flags); /* 首部长度+保留位+标志位 */
PACK_STRUCT_FIELD(u16_t wnd); /* 窗口大小 */
PACK_STRUCT_FIELD(u16_t chksum); /* 校验和 */
PACK_STRUCT_FIELD(u16_t urgp); /* 紧急指针 */
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END