2008-10-10 56 views
5

在.NET中搜索字符串非常好,但是當你需要搜索的數據不是字符串時,你會做什麼?搜索字節[]

我有二進制數據通過NetworkStream定期塊到達。數據包是二進制的,但它們都以字節的簽名序列開始。我將這些塊積累到一個更大的緩衝區中並查找數據包的開始簽名。

我真正想要的是byte[]相當於String.IndexOf(ss)方法。我有一個討厭的感覺,我將不得不使用循環和狀態機自己實現這一點。

有什麼建議嗎?超過你!


如上所述,Array.IndexOf(byte)至少可以爲我節省一個顯式循環。自發布以來,我發現找到第一個簽名字節,然後探測最後一個簽名字節應該在哪裏的匹配,然後如果它們都匹配,則嘗試對字符串的其餘部分進行蠻力比較。這種方法的優點是便宜地拒絕錯誤匹配,並允許當我有部分簽名等待另一個塊時便宜地拒絕。

谷歌透露,上述輝煌的計劃是一個退化的「KMP」或Knuth-Morris-Pratt算法的情況。在光明的一面,如果Knuth把他的名字寫在上面,它可能是油脂閃電,爲什麼每當我有一個好主意Donald Knuth在25年前想到它時呢?

既然我不能給Donald Knuth評分,我猜他們會去尼爾森。

回答

3

您可以使用Array.IndexOf查找單個字節。

但是,我會告誡你,一些有效的數據可能會意外地成爲你的簽名並完全甩掉你的應用程序。我認爲更好的解決方案是始終發送一個包含分組大小的四字節整數。然後讀取很多字節以清除該數據包的緩衝區。

如果您使用的是TCP完全能夠接受踢客戶,如果他們撒謊,包大小或請求的內存:)

+0

我不會寫協議,我正在和傳統硬件通話。我確實要寫下一個版本,而且我已經明確指出了你的建議。 – 2008-10-10 07:09:04

0

你可以使用非託管/不安全的代碼愚蠢的量?如果是這樣,我可能會建議尋找使用指針算術搜索您的字節數組。這就是字符串的有效性。你可以做類似的事情。

另一種解決方案可能是使用字典存儲您的數據包數據。鑰匙是你的簽名。然後它相當快速且容易找到它。有幾種方法可以將字節作爲關鍵字,比如base64string,simepl wrapper(如果你這樣做使用KeyedCollection)等。

+0

事實上,非託管代碼是PITA,因爲我們有一個混合的32/64環境。這對於純粹的託管代碼來說是多麼少麻煩。 Catch-22:我需要簽名才能將數據流解析爲數據包。 – 2008-10-10 07:05:32

2

用於查找字節數組和字符串中的模式的最快算法是Boyer-Moore和簡單Boyer-Moore(當模式與正在搜索的文本顯着不同時很有用)。我用它在Java中實現了一個快速的mime解析器。 code可以很容易地移植到.Net(許可證是LGPL)。