2013-10-19 52 views
4

我有一個TCP-Brodcast - 服務器與libevent的編碼,從而執行以下操作:將數據寫入多個插座一次(一個系統調用)

Read data from a client 
... 
Transform the data 
... 
//Write data to all connected clients 
for (int i = 0; i< connected clients; i++){ 
    // write Syscall for every client 
    write(clientfd[i], "Transformed Data", lenofdata) 

} 

現在我想提高性能並降低系統的計數調用。 而是在序貫方式來進行系統調用每次我寫一個插座轉換後的數據寫入到每一個插座的,我想只用一個系統調用是這樣寫數據到我所有的連接的客戶端:

Read data from a client 
... 
Transform the data 
... 

// one single write Syscall for all connected clients 
write(arrayWithManyClientFds, "Transformed Data", lenofdata) 

這可能嗎?

編輯: 起初我以爲我找到了一個叫lio_listio會將其被描述here爲beeing的功能,這是「非常重要,因爲它意味着你可以在一個單一的系統調用中啓動大量的I/O的系統調用(意思是一個內核上下文切換)「。

Unfortunalty lio_listio會將()接縫不被工作插座,因爲它是表示here「AIO讀取和插座寫[不支持](不返回一個明確的錯誤,但悄悄默認爲同步或相當的非-AIO行爲)」

,所以我還在尋找一個解決方案,如果有一個!

+0

想象一下,您的服務器有兩個客戶端,一個網絡連接速度非常快,一個網絡連接速度非常慢。 (假設的)TCP writeMany()函數如何處理該問題? –

+0

好點。但是它可以通過異步非阻塞write()(如aio_write)來解決,其中內核處理對每個文件描述符的寫入。你怎麼看? –

+0

我對aio_write()不太熟悉,但我認爲這隻會延遲問題的發生。如果你發送的數據量很大,慢速和快速客戶端的「當前發送位置」將會不斷增加,所以內核最終不得不緩衝RAM中的千兆字節數據(直到慢速客戶端已準備好接收它),或者它必須降低將數據發送到速度最慢的客戶端可以接收的速度。這些都不是一個非常令人滿意的解決方案。 –

回答

4

不,不是。但是,如果它讓你感覺更好,那麼系統調用只會將數據複製到內核緩衝區,然後操作系統將自己的時間寫入IO時間並且比CPU慢得多,因此性能問題是最小,我懷疑它會成爲你的瓶頸。 另一種可能的解決方案是使用broadcast addressMulticast - 但這些解決方案在大多數路由器和網絡上都存在問題並且受阻。

不支持這種功能的原因之一是IP數據包不能輕鬆發送給多個收件人 - 每個數據包都包含接收方的MAC和IP地址,每個收件人都可能正在收聽一個不同的TCP端口也是數據包的一部分,因此對於每個接收者來說,數據包的處理是不同的,因此在內核或用戶程序中需要在套接字上進行循環 - 而且這不是必需的或合理的功能爲內核執行。

+0

你說「一個IP數據包不能輕鬆發送給多個收件人」。不是_easily_,因爲使用廣播地址或多播(你暗示)這樣做,但是很複雜和/或在實際的網絡環境中不起作用?你能擴展嗎? – oberstet

+0

@immortial:*「這裏的性能問題很小」* ......如果我沒有錯,內核可以在從系統調用返回時執行待處理工作(例如,softirqs)。這使應用程序體驗到進一步的延遲,這可以通過使用單個系統調用來避免。 – Claudio

0

如果所有的客戶端都在同一個網絡上,你可以使用UDP套接字與SO_BROADCAST選項。

當一臺計算機做信息「發送」,所有其他計算機會「的recv」的消息,並在必要時更新這種方式。

此外,對於@immortal指出,由於同樣的原因,這不會郵件是否要經過路由器,以達到客戶的工作。

您可以創建一組接收廣播消息,然後每個代理將使用TCP轉發給客戶端基於UDP代理。這樣至少可以減少發送消息的進程的負載,並且可以由網絡上的其他計算機共享。

+0

稍微更精細的版本將使用多播數據包而不是廣播;這種方式(至少在具有智能交換機的網絡上),UDP數據包只會發送給實際想要接收它們的收件人。 (相比之下,廣播數據包總是進入本地網段的所有內容,浪費帶寬和CPU週期) –