TCP:因性恶而复杂,先恶后善反轻松
TCP协议之所以复杂,是因为他认为网络环境是恶劣的,丢包、乱序、重传、拥塞都是常有的事,发出的数据很可能到达不了目标设备,因此需要从算法层面保证其可靠性。
TCP包头格式

源端口和目标端口:保证数据发送给特定的应用。
包的序号:解决乱序问题。
确认序号:解决丢包问题,发送出去的数据一定要有确认,否则应该重新发送直到送达。
状态位:SYN表示发起连接,ACK表示回复,RST是重连,FIN是结束连接。TCP是面向连接的,因此双方会维护连接状态,带有状态为包的发送会引起双方状态的变更。
窗口大小:流量控制,通信双方各声明窗口标识当前处理能力,进而控制发送频率保持在合理范围。拥塞控制:即提出要求又不强人所难。
因此:
顺序问题,稳重不乱;丢包问题,承诺靠谱;连接维护,有始有终;流量控制,把握分寸;拥塞控制,知进知退。
TCP的连接维护
TCP建立连接:三次握手
A: Hello, this is A!
B: Hello, this is B!
A: Hello, B!
通常成为“请求---->应答---->应答之应答”三个回合。
假设网络通路是不可靠的,A发起连接,当第一个请求没有收到回复的时候可能发生:丢包、超时、B没有响应不想建立连接。此时A无法确认结果,于是重发。
终于B收到了A发送的包,但是包到达B这件事A并不知道。A可能继续重发。
B知道A想建立连接,如果B不愿意建立,那么A重试一段时间后放弃,连接建立失败,没有问题。如果B愿意建立连接,则会发送应打包给A。
这个应答包能不能到达A,B一无所知。那么B自然不能认为这个连接建立好了。特殊情况,假设B认为连接成功建立,B收到了A在重试过程中发送的请求包,会误认为是正常的请求,明显不合情理。因此两次握手肯定不行。
B的应答包也会发送多次,但只要有一次到达A,A就认为连接建立,因为A发出的信息有去有回。对于B来说,发出的消息只有收到回复才能确定连接建立,因此需要A发送确认包给B。
因此至少需要三次握手。
三次握手除了建立连接之外,还沟通了一件事情:TCP包的序列问题。A要告知B我发送的包要从那个序列号开始,B同样需要告知A我发的包要从那个序列号开始。每个连接都要有不同的序列号,序列号随时间变化而变化,可以看成是32位计数器,每间隔4ms加1.

TCP四次回收
A: Hello, I will exit.
B: Got it.
B: Hello, I will exit, too.
A: Ok, ByeBye!

A发送即将退出后进入FIN-WAIT-1状态,B收到之后发送给A”知道了“之后进入CLOSE-WAIT状态。
A收到B的回复,进入FIN-WAIt-2状态;此时如果B跑路,A会一直停留在这个状态。
B处理玩自己的事情,发送给A我也要跑路了,A收到之后会给B一个回复表示收到。按说B可以直接跑路了,但是假如B收不到回复的确认信号,会重发给A告知我也要跑路了,如果A直接走了,B就永远也收不到ACK了。因此TCP协议要求A最后等待一段时间TIME-WAIT,这个时间足够长,足以收到B重发的包并回复ACK信号。
A直接跑路还可能存在问题:A的端口空闲并被其他应用占用,那么这个应用汇收到B发过来的包。为了双重保险,要求A等待足够长的时间进而保证B发送的包都消失,再空出端口。等待时间设置为2MSL(Maximum Segment Lifetime,报文最大生存时间),协议规定为2分钟,常用30秒、1分钟、2分钟。
如果B超过了2MSL时间还没有收到ACK,则会重发,会继续发FIN,A收到后表示我已经等了足够长的时间了,你发给我我也不认了,会发送给RST给B,B就知道A已经退出了。
TCP状态机

小结
主要关注顺序问题、丢包问题、连接维护、流量控制、拥塞控制。
连接的建立三次握手断开四次挥手。