2008-12-23 48 views
1

我在Windows上完成了相當多的編程,但現在我必須編寫第一個Linux應用程序。在Linux應用程序中的建築建議

我需要使用UDP與硬件設備對話。我必須每秒發送60個數據包,大小爲40個字節。如果我在1秒內發送少於60個數據包,就會發生不好的事情。 數據包的數據可能需要一段時間才能生成。但是如果數據沒有準備好發送出去,可以發送上次發送的相同數據。 計算機是一個命令行的唯一設置,只會運行此程序。

我對Linux不太瞭解,所以我希望能夠得到一個大概的想法,你如何設置一個應用程序來滿足這些要求。 我希望得到如下答案:

製作2個線程,一個用於發送數據包,另一個用於計算。

但我不確定這是如此簡單(也許是)。也許用一些從共享內存發出數據包的守護進程更可靠,然後讓另一個應用程序進行計算?如果它是一個多進程解決方案,你會推薦什麼通信機制? 有什麼方法可以讓我的應用比普通或類似的應用更具優先級?

PS:越防彈越好!

+0

既然你不知道UDP數據包是否到達(這是一種不可靠的協議),怎麼辦你知道你發送的60 +/-數據包到達了嗎?如果一秒鐘發送61個數據包會發生什麼? 59怎麼樣?其他號碼? – 2008-12-28 02:47:12

回答

0

我發佈了這個答案來說明一個完全不同的「明顯」方法,希望有人發現它正是他們所需要的。我沒想到它被選爲最佳答案!請謹慎對待此解決方案,因爲存在潛在的危險和併發問題...

可以使用setitimer()系統調用在指定的毫秒數後向您的程序發送SIGALRM(報警信號)。信號是異步事件(有點像消息),它會中斷正在執行的程序,讓信號處理程序運行。

當您的程序開始時,OS安裝了一組默認的信號處理程序,但您可以使用sigaction()安裝自定義信號處理程序。

所以你只需要一個線程;使用全局變量,以便信號處理程序可以訪問必要的信息併發送新的數據包或根據需要重複上一個數據包。

這裏是爲了你的利益的例子:

#include <stdio.h> 
#include <signal.h> 
#include <sys/time.h> 
int ticker = 0; 

void timerTick(int dummy) 
{ 
    printf("The value of ticker is: %d\n", ticker); 
} 

int main() 
{ 
    int i; 

    struct sigaction action; 
    struct itimerval time; 

    //Here is where we specify the SIGALRM handler 
    action.sa_handler = &timerTick; 
    sigemptyset(&action.sa_mask); 
    action.sa_flags = 0; 

    //Register the handler for SIGALRM 
    sigaction(SIGALRM, &action, NULL); 

    time.it_interval.tv_sec = 1;  //Timing interval in seconds 
    time.it_interval.tv_usec = 000000; //and microseconds 
    time.it_value.tv_sec = 0; //Initial timer value in seconds 
    time.it_value.tv_usec = 1; //and microseconds 

    //Set off the timer 
    setitimer(ITIMER_REAL, &time, NULL); 

    //Be busy 
    while(1) 
     for(ticker = 0; ticker < 1000; ticker++) 
      for(i = 0; i < 60000000; i++) 
       ; 
} 
+0

我認爲一般的建議是保持信號處理程序非常簡單? I/O(printf和發送UDP數據包)當然應該避免? – 2008-12-23 07:44:53

1

正如你所建議的兩個線程將工作。如果你在它們之間有一個pipe(),那麼你的計算線程可以在它們生成時提供數據包,而你的通信線程使用select()來查看是否有新的數據。如果不是,那麼它只是從緩存中發送最後一個。

我可能比簡單的問題有點......

3

我做了一個類似的項目:一個嵌入式Linux計算機上的一個簡單的軟件,以常規速度發出CAN消息。

我會去兩個線程的方法。如果另一個線程在計算這些塊時速度較慢,請給發送線程稍高的優先級,並再次發送相同的數據塊。在大多數系統(包括嵌入式系統)上,每秒UDP數據包相當寬鬆,所以我不會在優化線程和發送數據包之間的數據共享上花費太多的汗水。

其實我會說:保持簡單!我真的是系統中唯一的應用程序,並且您對該系統有合理的控制權,從複雜的IPC方案和其他技巧中無法獲得。保持簡單將幫助您以更少的缺陷和更短的時間生成更好的代碼,這實際上意味着更多的測試時間。

1

只要執行計算的負擔不是太大,使用一對線程的建議聽起來好像會起作用。

而不是像Cogsy所建議的那樣使用pipe(),我傾向於使用一個互斥來鎖定你用來包含計算線程輸出的一塊內存 - 將它用作線程之間的傳輸區域。

當您的計算線程準備好輸出到緩衝區時,它將獲取互斥鎖,寫入傳輸緩衝區並釋放互斥鎖。

當您的傳輸線程準備好發送數據包時,它會「嘗試」鎖定互斥鎖。 如果它獲得鎖定,請複製傳輸緩衝區併發送它。 如果它沒有獲得鎖定,請發送最後一個副本。

您可以通過使用「nice」並指定一個負調整數字來給予它更高的優先級來控制進程的優先級。請注意,您需要以超級用戶身份執行此操作(以root身份或使用'sudo')才能指定負值。


編輯:忘了補充 - this是一個關於linux上的pthreads的好教程。還介紹了互斥體的使用。

1

我不太明白你的60包/秒的要求有多難。每秒60個數據包的突發是否滿足要求?或者每個數據包之間需要一個1/60秒的時間間隔?

這可能會出現一些問題,但另一個重要問題是如何配置Linux機器。我自己會使用實時 Linux內核並禁用所有不需要的服務。除此之外,無論您選擇何種架構,您的應用程序在某個時候都會錯過一個數據包,這確實存在風險。

任何方式,兩個線程應該工作。

0

兩個線程會的工作,你需要確保你通過更新通過這樣的發送線程沒有看到它一半鎖定您的共享數據結構。

每秒60聽起來不太複雜。

如果您真的關心調度,請將發送線程的調度策略設置爲SCHED_FIFO和mlockall()其內存。這樣,沒有什麼能夠阻止它發送一個數據包(雖然如果其他東西同時在線上發送,他們仍然可能會晚出)

設備必須有一定的容差 - 60每秒數據包沒有問題,但設備的容差是多少?每秒20?如果設備如果沒有收到設備將會失敗,我會按照它要求的速率三次發送它們。

0

我會遠離線程並使用進程和(可能)信號和文件。既然你說「不好的事情」可能發生,如果你不發送,你需要避免鎖定和競爭條件。這對於單獨的進程和保存到文件的數據更容易。

沿着一個進程將數據保存到一個文件,然後重命名並重新開始。另一個過程是每秒拾取一次當前文件併發送其內容。

與Windows不同,您可以可以在打開文件時複製(移動)文件。

0

遵循長期的Unix最佳實踐:保持簡單和模塊化,分離操作,讓操作系統爲您儘可能多地完成工作。

這裏的許多答案都在正確的軌道上,但我認爲他們可以更簡單:

  • 使用兩個獨立的過程,一個創建數據並將其寫入標準輸出,和一個從stdin讀取數據併發送。讓基本I/O庫處理進程之間的數據流緩衝,並讓OS處理線程管理。

  • 首先使用定時器循環和僞造數據緩衝區構建基本發送方,然後以正確的頻率發送給設備。

  • 接下來使發件人從標準輸入讀取數據 - 您可以重定向文件中的數據,例如, 「sender < textdata」

  • 構建下一個數據生產者並將其輸出管送至發件人,例如, 「製作人|發件人」。

現在,您可以根據需要創建新的生產者,而不會干擾發件人一方。這個答案假定單向溝通。

保持答案儘可能簡單會讓你獲得更多的成功,特別是如果你還不是很流利的基於Linux/Unix的系統。這是一個學習新系統的好機會,但不要過度使用它。當工具可用時,很容易跳到複雜的答案,但爲什麼使用推土機,當一個簡單的t刀是充足的。互斥量,信號量,共享內存等都是有用和可用的,但會增加您可能並不需要的複雜性。

0

我同意這兩種線程方法。我也有兩個靜態緩衝區和共享枚舉。發送線程應該有這個邏輯。

loop 
    wait for timer 
    grab mutex 
    check enum {0, 1} 
    send buffer 0 or 1 based on enum 
    release mutex 
end loop 

另一個線程會有這樣的邏輯:

loop 
    check enum 
    choose buffer 1 or 0 based on enum (opposite of other thread) 
    generate data 
    grab mutex 
    flip enum 
    release mutex 
end loop 

這樣發送者總是有它發送數據的整個時間的有效緩衝。只有生成器線程可以更改緩衝區指針,並且只能在發送未進行時執行。此外,枚舉翻轉永遠不會花費太多的週期來延遲較長的優先級較高的發送者線程。

0

謝謝大家,我會用大家的建議。我希望我能選擇比1更多的答案!

對於那些好奇。我沒有設備的來源,它是一個專有鎖定系統。我還沒有做足夠的測試來看看每秒60個數據包有多挑剔。那就是他們所有有限的文檔都說「每秒60包」。由於設備的性質,數據包的爆發將是一件壞事。我想我可以通過發送超過60秒的時間來彌補偶爾錯過的數據包。