通信过程,本质上只有两类:事件触发(Event trigger)和定时器触发(Timer trigger)
以TCP连接为例:
事件触发
A主动发起对B的tcp连接(SYN),这是事件触发,是A创建socket调用connect()函数触发tcp连接
定时器触发
如果SYN在发给B的过程中丢失,还需要A后面的用户重新发吗?这样的话tcp协议栈也太不友好了。事实上tcp会缓存用户的连接指令,同时开启一个重传定时器,定时器超时,没有收到ACK+SYN,tcp会自动重传连接指令,这就是定时器触发
事件触发
B收到A的SYN请求,就会发ACK+SYN,这是事件触发
定时器触发
B发送ACK+SYN时同样担心丢失,所以B也会启动一个重传定时器,如果在超时时间内没有接收到A的ACK,说明B的ACK+SYN丢失,触发重传动作。如果收到ACK,则关闭定时器
事件触发
A接收到B的ACK+SYN,这是一个外部事件触发的动作,触发了:
- 关闭重传定时器
- 发送ACK
- 将TCP状态更新为Established
这里A在发送ACK后要不要启动重传定时器?
不需要
你想,如果启动了重传定时器,而B并不会对单独的ACK作为ACK响应,除非此时B有数据发送Data+ACK,如果B只接收数据而不发送数据,那么这个ACK不会有对应的确认ACK发送给A,那么这个重传定时器超时后又会发ACK给B,无限循环下去
为什么A发送ACK不需要关心是否到达B呢?
因为A发送ACK就已经进入Established,只要A发数据,就是ACK+Data,这个ACK+Data才会启动重传定时器
对于应用层提交给tcp的数据,这是事件触发,触发的动作是:
- 发送数据,并缓冲数据
- 为数据启动重传定时器
如果接收到对方ACK,事件触发的动作是:
- 关闭定时器
- 释放缓存
如果定时器超时也没有接收到ACK,则定时器触发,动作是:
- 重传数据
- 记录重传次数
如果重传次数满,比如重传8次,则是事件触发,动作是:
- reset或关闭tcp连接
- 通知应用层出错
总结
整个通信过程只需要一次用户输入(用户事件),接下来的通信过程全部依赖事件触发,定时器触发而产生的动作自动完成,不管顺利与否,无需用户干预