TCP包头格式:
源端口号和目标端口号和UDP一样,是不可少的,因为少了的话就不知道应该发给哪个应用了。
接下来是包的序号,这是为了解决乱序的问题
然后是确认号,发出去的包应该有确认,要不然不知道对方收到了。
接下来是一些状态位,SYN是发起一个连接,ACK是回复,RST是重新连接,FIN是结束连接等。TCP是面向连接的,因为双方都要维护连接的状态,这些带状态位的包的发送,会引起双方状态的更变。
窗口大小:TCP要做流量控制,通信的双方各声明一个窗口,标识自己当前能够处理的能力,别发得太快,也不要发得太慢。
通过TCP头的解析,我们要重点关注一下几个问题:
- 顺序问题
- 丢包问题
- 连接维护
- 流量控制
- 拥塞控制
TCP的三次握手
对于所有的问题,首先都要建立一个连接,TCP的连接建立,常常称为三次握手:
一开始客户端和服务端都处于CLOSED状态,先是客户端主动监听某一个端口,处于LISTEN状态,然后客户端主要发起连接SYN,带上了序列号,之后处于SYN_SENT状态,服务端收到发起的连接后,返回SYN,并且带上了ACK和序列号seq和值为客户端seq+1的ack,之后处于SYN_RCVD状态。客户端收到服务端发来的SYN和ACK后,发送ACK并带上seq和ack,之后处于ESTABLISHED状态,服务端收到了ACK的ACK之后,也处于ESTABLISHED状态
这样连接就建立好了,就可以进行数据传输了
为什么是三次,不是两次呢,按理说两个人打招呼,一来一回就可以了,使用三次是为了可靠,确保对方收到了我的回复。
那么为什么不是四次呢?
假设现在的这个通路不靠谱,A向B发起了一个连接,当发起了第一个请求杳无信息的时候,会有很多可能性,如果第一个请求的包丢了,或者是饶了弯路,超时了,还有B没有响应,不想和A连接。
但是A不确定结果,于是A就继续发,终于有一个包到达了B,但是B收到了请求包,A不知道,于是A可能还会发。
B收到请求包后,就知道了A的存在,并且知道A要跟它建立连接,如果B不愿意,A在重试一阵子后就会放弃,连接建立失败;如果B是愿意跟A建立连接的,那么就会发应答包给A。
对于B来说,这个应答包发出去后,也不知道会不会达到A,这个时候B是不认为连接建立好了,因为应答包仍然会丢,会绕弯,或者A已经挂了。
而且还有一个现象是,如果只是两次握手,A和B建立连接后,进行了简单的通信,结束了连接,我们前面说过,A在请求连接的时候,可能会发很多次请求包,如果这个时候,那些绕路的请求包又回来了,B收到了连接,就会认为这是一个正常的请求,于是建立了连接,但是我们知道,这个连接不会进行下去的,也没有个终止的时候,纯属B单相思了,所以两次握手是肯定不行的。
现在回到正常的连接,B发送应答包后,很可能发很多次,但是只要有一个到达了A,A就认为连接已经建立好了,因为对于A来说,它的消息有去有回,这个时候A就会给B发送应答之应答,B也在等这个消息,只有等到这个消息,才能确认建立了连接,对于B来说,它的消息也是有去有回。
这样连接就建立成功了。
当然A的应答之应答也可能会丢,会绕路,甚至B挂了,按理说,还应该有一个应答