TCP头格式
TCP有六个状态位: SYN(Synchronize Sequence Number,同步序列编号):用于发起一个连接。 ACK(Acknowledgement):用于回复 RST(Reset):用于重新连接 FIN(Finish):用于结束连接 PSH(Push):推送比特 URG(Urgent):紧急
TCP连接的建立过程:三次握手
??理解三次握手,要明白一个现实,就是网络是不可靠的。终究TCP包是要被封装在IP包中的,IP传输本身就是不可靠的,TCP协议要想可靠,只有一个办法,重传。
??A要和B建立连接,发送一个建立连接的请求,如同“你好”,B如果收到了“你好”,也应该回复A“你好”。B的回复是必须的,否则,A不知道B是否可达,或者B是否愿意建立这个连接。当A收到B回复的“你好”的时候,A就可以确认它的包B能收到,并且B的包它也能收到,就可以认为连接已经建立好了,但是此时B并不知道A是否能收到它的回答,所以此时B还不能认为连接建立好,需要A再次告诉B,”我已经收到了你的回复”。这样A-B, B-A, A-B,就构成了3次握手。 ??简而言之,A和B都要确认自己发出去的信息能被对方收到。
- 一开始两端都处于CLOSED状态,B是服务端需要监听端口,监听后变成LISTEN状态。
- A发送一个SYN(你好)后状态变为SYN-SENT。
- B收到SYN后状态由LISTEN变为SYN-RCVD。给A回一个SYN,ACK(回复你好)。
- A收到这个SYN,ACK后状态变为ESTABLISHED,然后给B回ACK
- B收到ACK后状态变为ESTABLISHED,连接建立完毕。
三次握手除了建立连接,还沟通了TCP包序号的问题。 ??①A和B要告诉对方,包的序号从几号开始:A第一次发seq=x,第二次发seq=x+1;B第一次发seq=y。 ??②每次连接都要有不同的序号(避免某个包绕路后冲突),其实序号随时间变化,因为这个32位计数器要4个小时才会重复,超过了IP包头里的生存时间值(TTL)。
TCP连接断开的过程:四次挥手
断开连接因为涉及到数据的完整性,因此比建立连接要复杂。
一个正常的流程就是A和B说:“我没事儿了”,B回复一个“我知道了”,然后B对A说“我也没事儿了”,A说“我知道了”。A-B,B-A,B-A,A-B,四次挥手。
- A给B发送 “FIN”请求 后进入FIN_WAIN_1。
- B收到A的消息后,发送 “ACK”应答 后进入CLOSED_WAIT状态。这里B不能直接发送“FIN”,因为B可能还要处理未完成的事情,例如Buffer中的数据。
- A收到B的“ACK”应答后进入FIN_WAIT_2状态,如果此时B直接跑路,A将永远处于这一状态。(Linux系统设置了tcp_fin_timeout这个参数,设置了一个超过时间,可以处理该问题)。
- B发送“FIN”请求后进入LAST_ACK状态,A收到后发送“ACK”应答,要进入TIME_WAIT状态。A这个时候不能直接CLOSED, 因为要确保B能收到这个ACK。TCP要求A的等待时间TIME_WAIT足够长,保证即便B没收到ACK,B再发给A,A再发给B也来得及。
A直接CLOSED还会造成端口被新的应用占用,新的应用收到上个连接中B发过来的包,要等这些包全部过期才行。
TIPS: ??① A的TIME_WAIT设定为2MSL,MSL(Maximum Segment Lifetime,最长生存时间)是包在网络上生存的最长时间,超过这个时间的包将被丢弃。协议规定MSL为2分钟,实际常用为30s,1min,2min等。 ??②TCP包是基于IP的,而IP头中有一个TTL域,该字段用来表示IP数据包可以经过的最大路由数,每经过一个处理它的路由器此值就减1,当此值为0时,数据包就会被丢弃,同时会发送ICMP包通知源主机。
TCP状态机
③-②小结: ??①TCP头很复杂,但是主要关注五个方面:顺序问题、丢包问题、连接维护、流量控制、拥塞控制。 ??②连接的建立要经过三次握手,断开要经过四次挥手。
|