设计一个有限状态机及其思路

来源:互联网 发布:西瓜影音for mac 编辑:程序博客网 时间:2024/05/01 21:34

前言

我之前一直觉得状态机是一个比较难理解的概念。所以遇到相关的问题都会觉得自己理解得不是很透彻,上周一个同事在给我分析问题的时候,无意间就谈到了状态机的流程,在分析问题的时候,没想那么多,感觉很顺畅的感觉,后知后觉发现原来这就是状态机了!我对于状态机原理什么的不懂,只从自己的实践的角度来分析下怎么去设计一个状态机,以及是怎么一个流程。

有限状态机

在说明流程之前,我觉得先说说为什么需要状态机,同样,我只从我实践的角度来理解这个问题。
需要状态机的场景,基本上是因为一些runtime运行时场景中,在这其中,涉及到多个状态在不同条件下的迁移流程,以及一些特定事件的发生。举个例子的话,基本上在做通信相关的朋友应该都知道,在通信中,状态机的使用场景很广,因为在呼叫过程中,涉及到呼叫的状态迁移以及相关的流程处理。再比如,更经典的是TCP的有限状态机,如下图所示:

这里写图片描述

TCP的有限状态机不算简单,也不算复杂,就中等复杂吧。我想待会儿说完我自己写一个状态机的流程之后,就以TCP的有限状态机为例子来作为实战尝试一下。

设计状态

设计状态机的第一步,那就是设计状态,设计者应该对于自己的场景中,会有哪些状态有比较清晰的认识。对应上图中,所谓的状态就是黄色矩形所示的图形,其实这一步是最为困难的,需要对整个业务场景有很清晰的认识,考虑需要很全面,需要覆盖到场景业务中会出现的所有状态。

状态迁移路线

在有了状态表之后,那就是需要确认的是,状态的迁移路线,换句话说,状态一可以直接通过一次跃迁,到达哪一个状态,那就使用一个向量指向这个状态。注意这里的迁移一定是直接迁移,而不能是跨状态连接,也就是说,不能是状态一到状态2这中间有中间状态的迁移。

重新整理状态表

这一步主要是在绘制状态机图时,需要将状态设定在合理的位置,然后使用之前的状态迁移路线连接,这一步相当于是前两步的综合,不过很重要,最终的图示以这个为准,合理的状态布置除了便于理解之外,还利于代码的编写。

具体实例

以上就是我所理解的在实践中去设计一个状态机所需要的步骤,这其中没有什么理论的论诉,实践流程其实就是那么简单的几步,接下来我想以上图所示的TCP的有限状态机为例子来讲解下,这些步骤的具体实践流程。

在TCP的有限状态图中,宿主机因为是全双工的通信,所以既是客户机,也是服务端,那么为了讲解的清晰,这里以客户机的流程为主来讲解。

TCP有限状态机 客户机实例

首先想想一个TCP客户机需要哪些状态呢?

第一个,毫无疑问是 CLOSED 刚开始的时候,客户机肯定是处于关闭状态的,有开始那么就有发送阶段,客户机肯定是主动去和服务端通信的,所以这里就有一个发送状态SEND。我们都知道在实际开始数据通信之前,TCP是有一个连接建立过程的,就是俗称的三次握手过程,但是在状态机图中,这是没有必要的,因为这个过程并不能算一个状态。在完成了发送之后,在状态层面上说,下一个状态应该是一个持久态,就是数据传输状态,即ESTABLISHED。之后的迁移,即是连接的断开,就TCP来说,全双工必须要断开两端的连接,状态的设计很依赖场景,因为TCP的全双工的特点,所以才有了接下来的状态设计。第一步从客户机进行断开,这时候则有一个状态FIN_WAIT_1,为啥这么设计?因为这只是断开了从c-s的连接,还需要断开s-c的连接,若是服务端在回复了客户机之后,这代表服务端准备关闭了,这时候,就可以进入两端都断开的状态FIN_WAIT_2阶段了,这时候还不能直接进入CLOSED状态,因为客户机需要发出确认信息给服务端,这时候为了保证连接的正确关闭,需要TIME_WAIT状态来进行收尾,为什么需要这个状态,主要是考虑到网络状态是不确定的,服务端的FIN包可能会重传多次,需要正确处理这个状态。

从以上可以看出,状态机的设计,需要设计者非常清楚在自己的业务场景中的状态,只有清楚了所有可能的状态,接下里的步骤才有意义,这也算最重要的一个阶段吧。

列举出所有可能的状态:

  • CLOSED
  • SEND
  • ESTABLISHED
  • FIN_WAIT_1
  • FIN_WAIT_2
  • TIME_WAIT

接下来的工作便是通过这些现有状态进行状态机迁移图的绘制,以及整理工作了。注意以上只是c-s的流程,只是为了说明方便起见。

附带说一句,在状态机中,因为是runtime运行时的原因,状态的迁移万一没有按期望迁移,那么需要超时机制来保证迁移,所有在状态机的设计中有一个很重要的概念,那便是定时器,什么时候起一个定时器,什么时候超时都是具体的业务问题了,具体问题具体看待。

原创粉丝点击