在實際工作中,經常遇到狀態機的應用,尤其在網路協議部分,最為經典的就是tcp協議的狀態機:
實際上,很多網路協議都是有工作狀態的,不同階段所處不同的狀態,例如dhcp協議,路由協議,sip協議等等。這些協議在實現的時候多多少少會用到狀態機的原理,可能在實現上有較大的差別。我原來只是聽說過有這個原理,但只限於聽說,但具體實現以及它的優點更是不知所以;
這幾天在學習bfd協議的時候,bfd的核心部分就是使用狀態機來實現的,這就使我花點時間好好了解下狀態機實現的原理,這篇部落格主要介紹狀態機的最簡單實現,因為網上沒有找到想要的實現,所以決定自己寫幾個例項並記錄下來。
這幾個例項是參照的栗子做的,只是這篇文章全是使用的switch-case實現的,所以我做乙個補充,使用另一種更符合狀態機的實現。
不是說有些問題必須使用狀態機,只是使用狀態機可以簡化問題,**的邏輯也比較清晰
如果要使用狀態機進行解決問題,首先要確定這個問題本事有幾個狀態,然後我們把所用的狀態做乙個列舉型別的定義,問什麼是列舉型別呢? 因為我們定義==狀態的目的就是把狀態當作索引值==,這可以說是狀態機實現的精髓了,因為它就是根據當前的狀態來確定下一步的行為。
例如:乙個問題有三種狀態,則可以使用這樣的定義:
enum
fsm_state;
定義事件,這個不是必須的。 我是參照bfd核心原始碼的狀態機實現來做實現的幾個栗子,定義事件的好處就是可以統一處理各種情況,不需要再每個狀態中再單獨判斷,這樣需要花費更長的時間去實現每個狀態中的函式。
事件是與狀態相對應的,簡單的說,從「狀態0」切換到「狀態1」是由某些特定事件導致的,同理從「狀態1」切換到「狀態2」是由另乙個事件導致的。 我們把引起狀態切換的條件稱為事件。
再舉個栗子:
tcp伺服器再收到客戶端發來的syn報文後,做出syn+ack的應答,我們就可以把==「收到syn」稱作乙個事件==。
確定好事件後,我們將也定義乙個事件的列舉型別,因為事件的作用就是作為另乙個索引。
例如:乙個問題有三個事件,則可以使用這樣的定義:
enum
fsm_events;
struct fsm_node
;
當然這只是個結構體,而真實的狀態機一般定義為乙個二維的陣列,為什麼是二維的? 從上文已經知道「狀態」+「事件」是同時作為索引值,因此這裡定義為二維的變數也是可以理解的。
栗子中定義的狀態機變數如下:
struct
fsm[state_num]
[event_num]=,
,},,
,},}
;
完整**在第乙個例項中。
fsm就是個二維陣列,只不過它儲存的是乙個結構體;我們是在它定義的時候進行的初始化。
理論上,每一種狀態下,所有的事件都有可能發生,所以每一種狀態下,我們定義了(事件種類event_num)個物件。
狀態變遷圖與流程圖比較類似,只不過它突出是的狀態和事件。畫狀態變遷圖是為了開發方便,思路更加清晰。
畫狀態變遷圖的好處是方便定義狀態機:每乙個狀態下發生不同的事件分別該如何處理以及下一狀態是什麼。
我們再具體例項中說明。
問題:除去乙個字串中連續的空格,只保留乙個。
狀態變遷圖:
**實現
#include
typedef
enum
state;
typedef
enum
events;
#define state_num 2
#define devent_num 2
intisnotspace_func1
(char
*str)
intisnotspace_func2
(char
*str)
intisspace_func1
(char
*str)
intisspace_func2
(char
*str)
struct
fsm[state_num]
[devent_num]=,
/*not_space*/
,/*is_space*/},
,/*not_space*/
,/*is_space*/},
};/*根據當前狀態和當前事件做索引,找到對應的處理情況;然後再獲取下一狀態*/
void
demo1()
}
結果:
root# .
/a.out
root# h e l l o, w o r l d;
問題:除去乙個字串中連續的空格,只保留乙個,但保留雙引號(「 」)內的所有字元。
狀態變遷圖:
**實現
#include
enum
fsm_state;
enum
fsm_events;
#define state_num 3
#define event_num 3
void
func1
(char
*str)
void
func2
(char
*str)
void
func3
(char
*str)
void
func4
(char
*str)
void
func5
(char
*str)
void
func6
(char
*str)
void
func7
(char
*str)
void
func8
(char
*str)
void
func9
(char
*str)
struct
fsm_test2[state_num]
[event_num]=,
,,},
,,,}
,,/* when first " is reached, the state is always state_2, only when the next " reached, next state is state_0*/,,
},};
void
demo2()
putchar(10);}
結果:
root# .
/a.out
root# h e l l o ,
"today is friday !!!" w o r l d .
定義了很多同樣的實現函式,只是為了說明每一種(狀態,事件)都有各自的處理情景,這個栗子只是巧合
狀態機的c語言基本實現框架就是這樣,後續如果有經典的狀態機實現,做更新處理。
C 有限狀態機
用乙個類定義事件和狀態 檔案 globalautodcl.h const int nbmaxaction 10 const int nbmaxstate 5 const int nbmaxevent 6 class globalautodcl typedef enum 用乙個抽象類定義一些陣列,ac...
有限狀態機
有限狀態機 finite state machine,fsm 又稱有限狀態自動機,簡稱狀態機,是表示有限個狀態以及在這些狀態之間的轉移和動作等行為的數學模型。狀態儲存關於過去的資訊,就是說 它反映從系統開始到現在時刻的輸入變化。轉移指示狀態變更,並且用必須滿足來確使轉移發生的條件來描述它。動作是在給...
有限狀態機
以前,只碰到過 陣列中所有數字只出現2次,只有乙個出現1次,找這個數的問題 每次迴圈異或陣列中元素,最後的結果就是single one。這次換作出現3次就懵逼了,主要原因,沒有使用過有限狀態機,應該說是連概念都沒有,所以這次一定要好好記錄一下 關於這道題的解釋discussion中woshidais...