2015-09-26 121 views
0

我試圖編寫一個RFC 2812兼容的C++ IRC庫。 我在客戶端本身的設計上遇到了一些麻煩。 從我讀到的IRC通信往往是異步的。我使用boost::asio::async_readboost::asio::async_write。 通過閱讀我收集的文檔,您無法在完成一個async_write請求之前執行多個async_write請求。因此,你最終會得到相當嵌套的回調。這不是打敗了做異步調用的目的嗎?使用同步調用來防止嵌套會不會更好?如果不是,爲什麼?其次,如果我沒有弄錯,每個boost::asio::async_write後跟一個boost::asio::async_read來接收服務器對發送命令的響應。因此,我的客戶端的函數需要一個回調參數,以便在客戶端收到響應後(例如發送另一個消息...),該類的用戶可以執行某些操作。C++ IRC客戶端設計

如果我要繼續使用異步來實現此操作,我應該保留一個std::deque<std::tuple<message, callback>>並且每次boost::asio::async_write完成,並且隊列中有一個元組,並且出隊併發送消息,然後引發回調?這是實現這個系統的最佳方式嗎?

我在想,因爲消息一直在發送,所以我將不得不實現某種偵聽器循環來排隊響應,但是如何將這些響應與觸發它們的特定命令關聯?或者在這種情況下,響應只是來自另一個用戶的信道消息?

回答

2

IRC協議是一種全雙工協議。因此,應該始終監聽期望命令處理的服務器連接。有人可能會認爲,應該主要使用從服務器接收的消息來更新狀態,而不是將請求和響應關聯起來,因爲服務器可能不會對命令做出響應或可能比預期的響應晚得多。例如,可以發出WHOIS命令,但在接收到對WHOIS的響應之前接收多個PRIVMSG命令。對於聊天客戶端,用戶可能期望在等待對WHOIS的響應時能夠接收聊天消息。因此,有一個async_write()async_read()調用鏈可能不是理想的處理協議。

對於給定的插座中,短耳文件並建議不要啓動額外的讀操作,如果有一個優秀的組成讀操作,並不觸發額外寫入操作,如果有一個優秀的組成寫操作。排隊消息並從隊列中獲取異步調用鏈過程是實現此建議的好方法。考慮閱讀這個answer一個很好的解決方案,使用一個隊列和一個異步調用鏈。

此外,要知道,服務器甚至可以在活動連接發送PING命令。當客戶端使用PONG命令進行響應時,可能需要在出站隊列的前端附近插入PONG命令,以便儘快將其發送出去。

+0

所以你說我應該有一兩個'的std :: deque的<性病::組<消息,回調>>'和一個'的std :: deque的<性病::組<回覆,回調>>' ? 另外我應該產生一個線程來阻塞和不斷閱讀,並填寫答覆隊列?或者,遞歸調用async_read? 更新狀態是什麼意思 - 你能舉個例子嗎? 至於whois或ping命令,我可以在接收到特定回覆(如這些回覆)時「掛鉤」發送特定消息的例程。 –

+0

@FranciscoAguilera IRC協議本質上是異步的,所以我不會建議阻止調用。該協議也不是特定於何時需要發送對命令的回覆,並且一些服務器實現可能不發送迴應。我認爲通過事件來處理服務器命令會更加健壯(例如,當接收到「JOIN」命令時調用'on_join'),而不是嘗試管理如此接近協議層的回調(客戶端可能會收到'JOIN'不響應客戶端發送的「JOIN」命令的命令)。 –

+0

對,但你如何建議我收到這些命令?我需要調用async_read,不是嗎?我應該循環調用async_read從它的回調檢查數據讀取整個客戶端? –

1

這是不是打敗了做異步調用的目的?

通常的解決方案是使用鏈:

Why do I need strand per connection when using boost::asio?

你可以自由地排隊上使用(隱式)strand¹同一IO對象的多個異步操作。

使用鏈確保完成處理程序在同一個邏輯線程上被調用。


在協議

你確實可以發送下一個之前保持的命令隊列,等待每個命令的響應。

你可能是這個有點聰明,如果你能發現,由於不同類型的答覆的相關性,但隨後你需要保持每類型的命令隊列。我會考慮過早的優化。