2010-07-19 62 views
6

我重新訪問的通信協議解析器設計的字節流(串行數據,在時間接收的1個字節)。二進制通信協議解析器設計用於串行數據

包結構(不能改變)爲:

|| Start Delimiter (1 byte) | Message ID (1 byte) | Length (1 byte) | Payload (n bytes) | Checksum (1 byte) || 

在過去,我已經在程序狀態機方法實現這樣的系統。隨着數據的每個字節到達,狀態機被驅動以查看輸入數據一次一個字節地進入有效數據包的位置/傳輸數據,並且一旦整個數據包組裝完成,基於消息ID的切換語句執行消息的適當處理程序。在一些實現中,解析器/狀態機/消息處理程序循環位於其自己的線程中,以免給串行數據接收的事件處理程序造成負擔,並且由指示字節已被讀取的信號觸發。

我想知道是否有一個更優雅的解決這個通病,利用一些C#和麪向對象的設計更現代的語言功能。任何可以解決這個問題的設計模式?事件驅動vs輪詢還是組合?

我很感興趣地聽到你的想法。謝謝。

Prembo。

回答

4

首先我會從數據流中讀取器(這樣我就可以不用寫處理流測試)分隔包分析器。然後考慮一個基類,它提供了讀取數據包和寫入數據包的方法。

此外,我將建立一個字典(一個時間才把它重新用於未來的呼叫),如下所示:

​​

編輯:這到底是怎麼回事的幾點說明:

第一:

[Accepts(5)] 

這條線是C#的屬性(由AcceptsAttribute定義)表示,所述FooMessage類接受的5.

第二消息ID:

是字典被在運行時通過反射建造。你只需要做一次這樣的事情(我會把它放到一個單例類中,你可以把一個測試用例放到它上面來運行,以確保字典的正確構建)。

三:

var m = messages[5](); 

此行得到以下編譯lambda表達式了字典,並執行它:

()=>(Message)new FooMessage(); 

(演員陣容是必要的,.NET 3.5,但不是由於4.0對於如何工作的協變變化,在4.0中,類型Func<FooMessage>的對象可以被分配給類型爲Func<Message>的對象。)

這lambda表達式被賦值線字典制作過程中內置:

Value = (Func<Message>)Expression.Lambda(Expression.Convert(Expression.New(t), typeof(Message))).Compile() 

(這裏的轉換是必要的投編譯lambda表達式Func<Message>

我做了這種方式,因爲我碰巧在那個時候已經有了我可以使用的類型。你也可以使用:

Value =()=>(Message)Activator.CreateInstance(t) 

但我相信,這將是比較慢(這裏的轉換是需要改變Func<object>Func<Message>)。

四:

.SelectMany(o => o.Keys.Select(key => new { Key = key, o.Value })) 

這樣做是因爲我覺得你可能在將不止一次AcceptsAttribute更上一個類值(接受每班超過一個消息ID)。這也具有忽略不具有消息id屬性的消息類的好的副作用(否則Where方法需要具有確定該屬性是否存在的複雜性)。

+0

嗨比爾,謝謝你的回答。我試圖讓我的頭靠近它! 什麼... [接受(5)] ...表示法? 字典是否在運行時被反射填充? – Prembo 2010-07-20 04:58:40

+0

感謝您的詳細解釋。我學到了很多! 這是一個非常優雅和可擴展的解決方案。優秀。 我 – Prembo 2010-07-27 06:55:25

1

我通常做的是限定一個抽象基類消息並從中該類密封的消息。然後有一個消息解析器對象,它包含狀態機來解釋字節並構建適當的消息對象。消息解析器對象只有一個方法(將傳入的字節傳遞給它)以及可選的事件(在完整消息到達時調用)。

你就必須處理實際消息兩個選項:

  • 上在基站消息類定義一個抽象方法,在每個派生消息類別的覆蓋它。在消息完全到達後,讓消息解析器調用此方法。
  • 第二個選項較少面向對象,但可能更容易處理:將消息類保留爲數據。消息完成後,通過以抽象基類消息類作爲其參數的事件發送出去。除了switch語句之外,處理程序通常會將其播放到派生類型中。

這些選項中的兩者在不同的情況下非常有用。

+0

謝謝您的建議Stephen。這是一個非常容易實施的方法。 – Prembo 2010-07-27 07:17:52

2

我對派對有點遲到,但我寫了一個框架,我認爲可以做到這一點。在不瞭解協議的情況下,我很難編寫對象模型,但我認爲這不會太難。看看binaryserializer.com

+0

感謝分享 - 我會看看。 – Prembo 2013-03-08 10:55:18

+0

沒問題,讓我知道如果它有幫助,或者如果我需要修復一些東西:) – Jeff 2013-03-23 23:41:58