2015-07-21 158 views
0

我目前正在使用C++編寫的涉及UDP實時連接的項目。我從控制計算機接收UDP數據包,其中包含用於啓動/停止從IMU讀取數據並將數據發送到控制計算機的無限while循環的命令。UDP實時發送和接收來自控制計算機的Linux命令

我的問題如下:首先,我使用recvfrom()和read()從循環中實現了一個退出條件,但控制計算機每秒發送一個UDP數據包,這是延遲整個循環併發送數據在5ms的期望的時間間隔內是不可能的。

我試圖通過使用fcntl(fd, F_SETFL, O_NONBLOCK);並只使用read(),它實際上工作正常,但我不確定這是否是一個明智的想法,因爲我不再檢查錯誤,以解決此問題。有沒有什麼優雅的方式來解決這個問題?我想過使用Pthreads或類似的東西,但是我從來沒有使用線程或並行編程,所以我不得不花一些時間來學習。

我很感激你可以給我的任何建議。

這裏是一個代碼示例:

//include 
... 

int main() { 

RNet cmd;    //RNet: struct that contains all the information of the UDP header and the command 
RNet* pCmd = &cmd; 
ssize_t b; 
int fd2; 
struct sockaddr_in snd; // sender is control computer 
socklen_t length; 

// further declaration of variables, connecting to socket, etc... 
... 

fcntl(fd2, F_SETFL, O_NONBLOCK); 

while (1) 
{ 
    // read messages from control computer 

    if ((b = read(fd2, pCmd, 19)) > 0) { 
     memcpy(&cmd, pCmd, b); 
    } 

    // transmission 

    while (cmd.CLout.MotionCommand == 1) // MotionCommand: 1 - send messages; 0 - do nothing 
    { 
     if(time_elapsed >= 5) // elapsed time in ms 
     { 
      // update sensor values   
      ... 
      //sendto() 
      ... 
      // update control time, timestamp, etc. 
      ... 
     } 

     if (recvfrom(fd2, pCmd, (int)sizeof(pCmd), 0, (struct sockaddr*) &snd, &length) < 0) { 
      perror("error receiving data"); 
      return 0; 
     } 

     // checking Control Model Command 

     if ((b = read(fd2, pCmd, 19)) > 0) { 
      memcpy(&cmd, pCmd, b); 
     } 
    } 
} 

}

回答

0

我真的很喜歡 「上的多個線程阻塞調用」 的設計。它使您可以擁有獨特的獨立任務,而且您不必擔心每個任務如何幹擾他人。它可能有一些缺點,但它通常很適合許多需求。

要做到這一點,只需使用pthread_create爲每個任務創建一個新線程(您可以保留一個任務的主線程)。在你的情況下,你應該有一個線程來接收命令,另一個發送你的數據。您還需要接收線程通知發送線程的命令。要做到這一點,你可以使用一些同步工具,比如互斥鎖。

總體而言,你應該有你的接收線程阻塞recvfrom,和發送線程等待互斥體的信號(等待被釋放互斥體,技術上)。當接收線程收到一個啓動命令時,它會發出互斥信號並返回recvfrom(可選地,您可以設置一個變量來向其他線程提供更多信息)。

作爲評論,請記住,UDP是一對多的,因此您的代碼會對發送給您的任何數據包(即使是來自某個隨機或惡意主機)作出反應。您可能需要使用recvfrom之後的遠程sockaddr進行過濾,或使用connect + recv。這取決於你想要什麼。

+0

非常感謝,我遵循你的建議,並使用pthreads和一個互斥體,它工作得很好!但是,你能否詳細說明你的最新評論?我使用我的遠程pc ip地址嘗試了'connect' +'recv'和'recvfrom'與遠程'sockaddr',但都沒有工作。沒有錯誤,但似乎'recv' /'recvfrom'正在等待數據包... – Fruchtknabe

+0

@Fruchtknabe關於遠程IP:要使用'connect' +'recv',您應該指定遠程IP,但也應指定遠程IP港口。這可以在客戶端完成,但對於服務器來說不太實際。 'recvfrom'後面的過濾器只是一個自定義過濾器,用於檢查數據包的來源。這是你自己在recvfrom後自己做的檢查。 'recvfrom'用遠程主機填充'sockaddr',並檢查它是否合理,因爲你不想處理來自隨機主機的意外數據包。這是全部可選的,以保證魯棒性/安全性。 – ElderBug

+0

嗯,我確實指定了遠程IP以及端口,但它沒有工作。不幸的是,我對服務器/客戶端不是很熟悉。在我看來,控制計算機將是發送命令的「服務器」,並且我在「客戶端」上接收命令。無論如何,我被告知我不必擔心安全問題,但我想知道我做錯了什麼。 – Fruchtknabe