TCP协议分析---让你进一步的理解
TCP包头格式
注:
源端口号和目的端口号 | 源端口号和目的端口号是不可少的,这和UDP是一样的。这两个的作用就是将数据发送给指定的应用。 |
包的序号 | 编号是为了解决数据的乱序问题,做到哪个数据先来的,哪个数据是后到的。 |
确认序号 | 发出的包应有确认,解决的丢包问题,如果没有就需要重新发送 |
状态位 | SYN: 是发起一个连接; ACK : 是回复 ; RST:重新连接;FIN: 结束连接 |
窗口大小 | 为了解决流量控制,标识当前能处理能力的大小,不要发送太快,装不下;发送太小,用户体验太差 |
(拥塞问题) | 上面没有写 |
总结:
顺序问题,稳重不乱
丢包问题, 承诺靠谱
连接维护,有始有终
流量控制,把握分寸
拥塞控制,知进知退
TCP的三次握手:
例子:
A : 你好,我是A
B:你好A,我是B
A:你好B。
这就被称为“请求-应答-应答之应答”的三个回合
注:
两次行不行 | 不行的,如果网络通路是不可靠的,当A发送一个请求后,可能在通路中就丢掉了,或者超时了或者B没有响应,两次的话,A不知道自己发送的请求结果,所以可能一直发,当B收到请求后,就知道了A想与自己通信,如果自己不愿意连接A,则不会回复A,这个没问题,如果需要连接A,则就需要对A进行回复,这就是应答之应答。 |
四次行不行 | 按照上面说的,应答之应答也会可能丢,所以四次是可以的,甚至更多次都可以,但是这样的话就无穷尽了,所以连接的话,三次基本就行了 |
三次握手出了双方建立连接后,还为了解决TCP序号问题:
A需要告诉B,我的请求是从哪个号开始的,同理,B也要告诉A,哪里开始的。
现在双方建立了连接,下面就是为了维护这个连接诶,就出现了下面这个状态机
上图步骤讲解:
一开始,客户端和服务端都处于CLOSED状态,先是服务端主动监听某个端口,处于LISTEN状态,然后客户端主动发起连接SYN,之后处于SYN-SENT状态。服务端收到发起的连接,返回SYN,并且ACK客户端的SYN,之后处于SYN-RCVD状态。客户端收到服务端发送回的SYN和ACK后,发送ACK的ACK,之后处于ESTABLISHED状态,因为已经一收一发成功了。服务端收到ACK的ACK之后,处于ESTABLISHED状态,因为它也一收一发了。
下面讲讲TCP的四次挥手
建立连接作为开始,当然结束也是个比较重要的事情。
同样还是上面的例子:
A: B啊,我不想玩了
B: 哦,你不想玩了,我知道了
注: 这个时候A不想玩了,所以A不会在发送数据,但是B能不能在ACK的时候,直接关闭呢。这个时候是不行的,因为这时候相当于A已经做完了自己的事情,但是B没有处理完自己的事情(处理A发送的请求或者其他的请求),因此这时候被称为半关闭状态。
对于A, 可以选择不接受数据了,也可以选择接收数据,等待B的主动关闭
B: A 啊,好吧我也不想玩了,拜拜
A: 好的,拜拜
(这时候就是完整的关闭了。下面分析一下当中的异常情况)
A 开始说“不玩了”,B 说“知道了”,这个回合,是没什么问题的,因为在此之前,双方还处 于合作的状态,如果 A 说“不玩了”,没有收到回复,则 A 会重新发送“不玩了”。但是这个 回合结束之后,就有可能出现异常情况了,因为已经有一方率先撕破脸。
一种情况是,A 说完“不玩了”之后,直接跑路,是会有问题的,因为 B 还没有发起结束,而 如果 A 跑路,B 就算发起结束,也得不到回答,B 就不知道该怎么办了。另一种情况是,A 说 完“不玩了”,B 直接跑路,也是有问题的,因为 A 不知道 B 是还有事情要处理,还是过一会 儿会发送结束。
如何解决问题呢,TCP协议中看状态是很重要的,下面的断开连接的状态图
断开的时候,当 A 说“不玩了”,就进入 FIN_WAIT_1 的状态,B 收到“A 不 玩”的消息后,发送知道了,就进入 CLOSE_WAIT 的状态。
A 收到“B 说知道了”,就进入 FIN_WAIT_2 的状态,如果这个时候 B 直接跑路,则 A 将永远 在这个状态。TCP 协议里面并没有对这个状态的处理,但是 Linux 有,可以调整 tcp_fin_timeout 这个参数,设置一个超时时间。
还有下面的异常,下次分析,未完待续…
我们将建立连接的过程和断开连接的过程结合起来,就成了经典的TCP的状态机,如下图:
在这个图中,加黑加粗的部分,是上面说到的主要流程,其中阿拉伯数字的序号,是连接过程中 的顺序,而大写中文数字的序号,是连接断开过程中的顺序。加粗的实线是客户端 A 的状态变 迁,加粗的虚线是服务端 B 的状态变迁。
未完待续…
后面还将讲解TCP的五大问题