2010-06-04 76 views
9

我一直在試圖執行一些協議解碼器玩耍,但每次我碰到一個「簡單」的問題,我覺得我解決這個問題的辦法是不是最佳的,必須有一個更好的做事的方式。我正在使用C.目前我正在使用一些罐頭數據並將其作爲文件讀取,但稍後將通過TCP或UDP進行讀取。協議解析在C

這是問題所在。我目前正在工作中使用二進制協議。所有字段都是8位長。第一個字段(8位)是分組類型。所以我讀了前8位數據,並使用一個開關/情況函數來讀取數據包的其餘部分,因爲我知道它的大小/結構。然而,一些這些包都嵌套在他們的包,所以當我遇到特定數據包然後我要讀另一個8-16字節有另一臺交換機/箱,看看下一個數據包類型和和。 (幸運的是,數據包只能嵌套2或3個深度)。 只有一次我有整個數據包解碼我可以處理它交給我的狀態機處理。

我想這可能是一個更普遍的問題爲好。您需要從套接字一次讀取多少數據?越多越好?就像協議頭文件中的「相似」一樣?

因此,儘管這個協議是非常基本的,我的代碼是一大堆的開關/ case語句,而我做的從文件/插座,我覺得不是最優讀了很多。我的主要目標是儘可能快地製作這個解碼器。對於那些更有經驗的人來說,這是要走的路還是有更好的方式,我還沒有想出來呢?任何優雅的解決這個問題?

+0

非常感謝大家回覆!所有的回覆都很有用,給了我很多新的想法,正是我期待的! – NomadAlien 2010-06-07 13:37:09

回答

10

我推薦這種方法:

  1. 閱讀所有你可以從文件/插座(從實際協議分開的數據通信)
  2. 傳遞您已經閱讀到的程序來處理數據的數據

僞C代碼(想象destinationBuffer是circular buffer - 在需要分析大量輸入數據的應用情況下,我相信這樣的數據結構是至關重要的):

forever() 
{ 
    // this function adds data to the buffer updating it 
    read_all_you_can(destinationBuffer); 
    ... 
    handle_data(destinationBuffer); 
    // the buffer is automatically adjusted in order 
    // to reflect how much of the data was processed 
} 

通常最好是儘可能多地閱讀以獲得更多的性能。

+0

該死!我沒有想到一個循環緩衝區!這將解決我讀取數據的問題,並將數據包減半! – NomadAlien 2010-06-04 13:08:33

+0

@ nomad.alien這是處理流時必須的。你可以考慮幾乎任何東西 - 標準輸入,文件,套接字,管道 - 通常是UNIX中的文件描述符。 – INS 2010-06-04 14:28:35

1

多少數據你有從插座時間閱讀?

它是TCP還是UDP:它是面向流的還是面向數據包的?在知道消息類型之前,您是否有辦法知道消息的長度?如果沒有,你可以(例如,通過改變協議,以確保第一個字段包含/定義消息的長度?)

要做你正在做的事情,你需要從套接字讀幾次。如果你可以將整個消息讀入你自己的內存/ RAM中,然後在那裏解碼它,那麼它會更快/更容易;

+0

不幸的是,我不知道數據包的大小,直到我知道數據包的類型。它只是不「覺得正確」,我必須一次從套接字/文件中讀取8位數據以決定如何處理它。但我想我必須在某個地方做。這對我來說是第一次嘗試,所以可能是我沒有做錯任何事情,這是做到這一點的正確方法。謝謝回覆。 – NomadAlien 2010-06-04 13:03:58

+0

嗯,如果有一個描述數據包類型和大小的標題會更好,所以解析器將更少的努力來評估數據包內容 – pcent 2010-06-04 13:42:07

3

抵制過早優化的誘惑首先讓它工作,然後才應該考慮是否需要優化。如果你這樣做,科學地做:基準你的代碼,首先去找最低的水果,不要依賴直覺。

不要忘記你的操作系統可能會緩衝數據本身,w無論你是從文件或套接字讀取。儘管如此,反覆的系統調用可能是一個瓶頸,所以他們可能是一個簡單的優化勝利。在以前的工作場所,我們通過讓數據包頭明確地對其長度進行編碼(從不超過8k)來避免這個問題:通過這種方式,我們確切地知道需要多大量讀入數組,然後我們自己的緩衝代碼才能接管。

+0

我在想同樣的事情,但沒有數據包大小可言,因爲所有字段是8位字段,因此每個數據包都有一個固定的大小,除了允許嵌入字段的一個或兩個數據包,但這些嵌入字段的大小也是固定的,但這對於我來說是「難看」的部分,我必須一次讀取8位數據,通過幾個switch/case語句來了解我擁有的。 – NomadAlien 2010-06-04 13:06:45

2

請記住,read()是完全免費的暫時忽略你給它的大小,並嘗試讀取在拱對齊的邊界(8/16/32/64)。 read()可以自由地做到這一點,只要它返回您請求的確切數量(或更少)的字節。所以,幕後可能已經有相當多的優化了。

如果意識到這一點,所以你看是可能的,這往往意味着調用read()(自有或通過使用它的一些其他功能)最少的最大塊你馬上傾向於構建東西有可能處理一個數據包。

您越早在自己的地址空間獲取內存中的數據,越好 - 理想情況是儘可能少(直接或間接)調用read()。提示 - 如果您從文件描述符或流中獲取輸入,則使用read()

1

PADS旨在幫助您準確解決這類問題。它會爲你生成一個非常高效的C語言分析器。你寫了一個關於數據包格式的聲明性描述,PADS從那裏獲取它。

+0

謝謝諾曼。我會研究它。 – NomadAlien 2010-06-07 13:37:43