1、tcp的本性
tcp是一个悲观者,生下来就不信任网络,任务会发生丢包等,所以要从算法层面来保证可靠性。
2、TCP 包头格式
tcp的包头格式比UDP要复杂的多。
1.源端口号和目标端口号是不可少的,这一点和 UDP 是一样的。如果没有这两个端口号。数据就不知道应该发给哪个应用。
2.包的序号:是为了解决乱序的问题。不编好号怎么确认包到达的前后顺序。
3.确认序号:发出去的包需要ack,不然我也不知道有没有收到,如果没有收到,就应该重发,直到收到为止。
//这个可以解决不丢包的问题
4.状态位:
SYN:是发起一个连接
ACK 是回复
RST 是重新连接
FIN 是结束连接
//TCP 是面向连接的,因而双方要维护连接的状态,这些带状态位的包的发送,会引起双方的状态变更
注意:tcp虽然是靠谱的协议,但是网络环境不好的时候,对于IP层丢不丢包,它也没有办法,tcp唯一能做的就是不断地重试。
3、tcp的握手和技能
- tcp如何保证对于连接的信任呢,为什么需要握手呢,这就好比人与人之间不会第一次见面就信任对方吧,怎么也得握手几次吧。
- tcp做流量控制:通信双方各声明一个窗口,标识自己当前能够的处理能力,别发送的太快,也别发的太慢。
- tcp拥塞控制:对于网络是否拥堵,tcp是无能为力的,唯一能做的就是控制自己,也即控制发送的速度。
- tcp需要关注的点如下:
1.顺序问题 ,稳重不乱
2.丢包问题,承诺靠谱
3.连接维护,有始有终
4.流量控制,把握分寸
5.拥塞控制,知进知退
4、TCP 的三次握手
tcp连接的建立,又称3次握手,这是一个连接维护的问题,这样比较便于理解。
就是一个:“请求 -> 应答 -> 应答之应答”
A: 您好,我是A
B: 您好,我是B
A: 您好,B
为啥不是2次,4次?
1.假设网络环境不好,A发出了一个请求,包有可能会丢失或者请求超时了,于是A一直补发,直到B收到了请求,但是B收到的请求的时候,A可能不直到,所以A还会再发。
如果B收到了请求:
一是B不愿意建立练级,A会在一定时间后放弃
二是B愿意建立连接,像A发送一个ack,但是B发出去的包也会像石沉大海一样,也不知道A有没有收到。
另外还有一种可能,就是之前A发送包出去绕了一圈回来了,B接收到了,同样认为这是一个正常的请求,于是给出了响应,这事听起来也是挺离谱的。
so,2次握手是不可靠的!
2. 为啥不是4次?
不是4次不行,400次都行,只是这样会没完没了,理由如下:
B发出的消息可能会发送多次,A只要收到一次,就认为连接建立了,自己的请求有了响应,A发送一个应答的应答。
而B也在等这个消息,才能确认连接是否建立,只有等到了这个消息,对于B来说,这个消息是有始有终的。
对于应答的应答,也有可能会丢,会绕路,甚至B都宕机了,是不是需要B再这个基础之上再应答,如此的话,就是没完没了了。
只要双方的消息都有去有回,就基本可以了
1.大部分情况下,A 和 B 建立了连接之后,A 会马上发送数据的,这个时候很多问题就得到了解决。
//例如 A 发给 B 的应答丢了,当 A 后续发送的数据到达的时候,B 可以认为这个连接已经建立,或者 B 压根就挂了,A 发送的数据,会报错,说 B 不可达,A 就知道 B 出事情了。
2.如果A 比较坏,就是不发数据,建立连接后空着。我们在程序设计的时候,可以要求开启keepalive 机制,即使没有真实的数据包,也有探活包。
3.我们作为服务的提供者来说,如果A一直不发包,则可以主动关闭这个连接
5、包的序号问题
- 三次握手除了双方建立连接外,主要还是为了沟通一件事情,就是TCP 包的序号的问题。
- 每个连接都要有不同的序号。这个序号的起始序号是随着时间变化的。
- 序号,可以看成一个 32 位的计数器,每 4ms 加一。
- IP 包头里面有个 TTL,也即生存时间。