[081]由TCP/IP协议想到的思想
TCP/IP协议场景
说道TCP/IP协议想起了计算机网络书中举了一个红蓝军的通讯的问题。其场景如下:
红蓝军需要联手干掉山坡下敌人,双方约定某个时间一起进攻。
红军 <-------------> 蓝军
-----A:下午5点进攻-->
<---A+ack:收到消息---
-----A+ack+ack:----
由于任何一次通信都可能中断,通讯次数越多概率越大。于是在通讯可靠性和时间上做了一个折中,根据理论计算至少需要3次握手概率才达到比较满意的水平。
TCP协议本质上解决是不可靠信道上需要可靠传输信息的需求
如果信道是可靠的那么,那么不需要建立连接直接发送数据包也能够确保到达。但是实际网络中信道是不可靠的,需要通过3次握手来确定一条比较可靠的信道。
所以TCP连接建立后,都是沿同一条链路发送消息么?
连接释放为什么需要4次握手
通过4次握手的目的是确保通信双方都释放了连接,这样都不在发送数据包(防止网络上有大量的无用数据包,会增加网络的拥塞)。
TCP 序列号和确认号详解
TCP 通讯涉及到 客户端 client 和服务端 server,我们根据建立连接、发送数据、释放连接 3个阶段来描述序列号和确认号生成过程。
连接建立阶段大体上是,确认号=对方的序列号+1,序列号(除了第一次)=对方的确认号
客户端 服务端
序列号J | 确认号0 |置SYN标识 ---->
<---- 序列号k | 确认号J+1 | 置SYN和ACK标识
序列号J+1| 确认号 k+1 | 置ACK标识 ---->
数据传输阶段大体上是,确认号=对方序列号 + 数据报文长度,序列号= 对方确认号
TCP 协议的状态迁移
TCP建立连接一般是服务器启动服务进行监听,处理客户端发过来的请求。
其状态流转是:
client:close -> SYN-SEND -> ESTABLISH
server: close -> LISTEN -> SYN-RECV -> ESTABLISH
连接释放,我们以客户端主动断开连接为例。
客户端 服务端
发送报文 FIN_WAIT1 --> 此时服务器 CLOSE_WAIT(被动关闭)
FIN_WAIT2 <-- 服务器 ACK到客户端
TIME_WAIT (接收到最后确认后,客户端进入TIME——WAIT) <--- 再一次确认 LASTACK
当客户端等待2MSL后 发送ack 到服务端 --> close状态了
实际连接释放可以分为两个阶段,第一阶段:半连接 ,第二阶段:服务端也释放。
第一阶段:
客户端 发送fin报文 ---> 服务端
FIN_WAIT2 <---- ACK 报文
FIN_WAIT2 状态就是半连接的状态,表示客户端已经断开连接,服务端还有一些数据要发送。
第二阶段:
过了一段时间,服务端没有数据要发送了。
此时:
TIME_WAIT <--- 服务端发送FIN 报文 进入LAST_ACk状态 (服务端在发送了FIN后等待 MSL如果没有收到ACK则会重传FIN消息)
客户端发送 ACK ---> 服务端
客户端发出ACK后,等待ACK到达对方的超时时间MSL,等待FIN重传时间也是MSL,所以如果客户端2MSL时间段内没有收到FIN报文表示 服务端已经收到了ACK报文(已经关闭了)。
用概率来衡量不确定的东西
从“背景”那里分析,握手次数越多越好概率越高。但是实际情况下是可靠性和时效性之间的折中。而对于这些不确定的事情,我们最好的思路是以概率的方式来思考(而不是强迫症似的想100%)。
同样在微服务框架中,通过两台机器提供负载均衡。这样系统可用性为 p = 1-p1*p1,p1为系统宕机的概率。
思想的运用
TCP/IP 会有超时重传的机制,每发一段报文的时候会设置一个超时时间,如果超时会重发报文。
在我们的支付系统中,系统与系统之间的交互也是类似的思想。拿下单来举例:
网关 client .................... server 银行(比如支付宝)
ewallet 下单 ---> 发报文到银行
<--- 同步返回/或者异步通知 (ack) ,如果client timeout内没有接收到ack报文,则通过定时任务扫描网关中非success 的订单,调用查询接口(查询状态)。
---> response.write("success") (ack+ack) ,同样,如果server没有收到ack+ack 报文,则会重传 ack报文(即重新异步通知)。
参考:
http://www.cnblogs.com/chenboo/archive/2011/12/19/2293327.html