2012-09-03 59 views
5

我在我的udp服務器中使用相同的套接字,以便從某些端口上的客戶端接收數據,並且稍後在處理請求後使用ip :: ud :: socket響應客戶端:: async_send_to使用相同的udp套接字進行異步接收/發送

接收與async_receive_from同步完成異步。該套接字使用相同的ioService(畢竟它是相同的套接字) 該文檔沒有清楚地表明,如果一個人可以在同一個udp套接字從客戶端A(以異步方式)接收數據報,並可能發送另一個數據報給客戶端B異步發送) 我懷疑這可能會導致問題。我最終使用相同的套接字進行回覆,因爲我無法在回覆到另一個客戶端時將另一個套接字綁定到同一個服務器端口。

如何將另一個套接字綁定到同一個服務器端口?

編輯。我嘗試第二UDP套接字綁定到具有相同的UDP端口:

socket(ioService, boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), port)) 

當我做這第一次(用於服務器綁定「接收」插座),這是確定的,但試圖創建另一個插座第二次這樣的它在綁定時報告錯誤(asio拋出異常)

+2

請指定您的實際問題。您的設置是否正常工作,並且您正在尋找設計確認無誤的確認信息?或者它不工作,如果不是你觀察到什麼錯誤?或者你問如何將另一個套接字綁定到服務器端口? – mtrw

+0

@mtrw是否可以將另一個套接字綁定到同一個服務器端口?這樣我會使用不同的套接字發送重放。會發生什麼是,我認爲我的設置可能導致服務器故障。 – Ghita

+0

請修改您的問題以澄清而不是添加註釋 –

回答

14

可能有一個UDP套接字同時從一個遠程端點接收併發送到不同的遠程端點。但是,根據Boost.Asio Threads and Boost.Asio文檔,在單個對象上進行併發調用通常是不安全的。

因此,這是安全的:

 thread_1        | thread_2 
--------------------------------------+--------------------------------------- 
socket.async_receive_from(...);  | 
socket.async_send_to(...);   |

,這是安全的:

 thread_1        | thread_2 
--------------------------------------+--------------------------------------- 
socket.async_receive_from(...);  | 
             | socket.async_send_to(...);

但這被指定爲不是安全:

 thread_1        | thread_2 
--------------------------------------+--------------------------------------- 
socket.async_receive_from(...);  | socket.async_send_to(...); 
             |

要知道,有些功能如boost::asio::async_read,是由組成的,並有額外的線程安全限制。


如果任一下列條件都爲真,則沒有額外的同步需要發生,因爲流量將是隱式同步:處理程序中發生

  • 所有套接字調用,並io_service::run()只從調用一個單一的線程。
  • async_receive_fromasync_send_to只在同一個異步操作鏈中被調用。例如,傳遞給async_receive_fromReadHandler調用async_send_to,傳遞給async_send_toWriteHandler調用async_receive_from

    void read() 
    { 
        socket.async_receive_from(..., handle_read); --. 
    }             | 
        .-----------------------------------------------' 
        |  .----------------------------------------. 
        V  V          | 
    void handle_read(...)        | 
    {             | 
        socket.async_send_to(..., handle_write); --. | 
    }            | | 
        .-------------------------------------------' | 
        |            | 
        V            | 
    void handle_write(...)       | 
    {             | 
        socket.async_receive_from(..., handle_read); --' 
    } 
    

在另一方面,如果存在多個線程潛在地使所述插座併發呼叫,然後同步需要發生。考慮通過調用函數和處理程序執行同步,或者使用其他同步機制(如Boost.Thread的mutex)來執行同步。


除了線程安全性之外,還必須考慮對象生命週期的管理。如果服務器需要同時處理多個請求,那麼請注意每個請求 - >進程 - >響應鏈的bufferendpoint的所有權。根據async_receive_from的文檔,呼叫者保留了緩衝區端點的所有權。因此,通過boost::shared_ptr來管理對象的生命週期可能會更容易。否則,如果鏈條足夠快以致不需要併發鏈,則它簡化了管理,允許每個請求使用相同的緩衝區端點


最後,​​類允許套接字綁定到已在使用中的地址。不過,我不認爲這是一個適用的解決方案在這裏,因爲它一般用於:

  • 對於TCP,以允許一個進程重新啓動,並聽取了相同的端口,即使端口處於TIME_WAIT狀態。
  • 對於UDP允許多個進程綁定到相同的端口,允許每個進程通過組播進行接收和廣播。
+0

相當令人印象深刻的答案。我的情況我只是說我只有一個ioService線程(主),但即使async_receive_from/async_send_to不能被稱爲交錯,其中一個可以在另一個完成之前調用(完成對另一個的處理程序)。這是因爲我做了處理,以便在另一個與ioService線程有關的線程中進行說明。 – Ghita

+0

另一件事。它在哪裏指定端點類必須以特定方式處理。一旦我在async_receive_from中接收到一個端點作爲輸出參數,我會使用拷貝構造函數將它作爲一個「狀態」傳遞給它(以便我知道在哪裏稍後響應),直到我需要發送響應爲止。 – Ghita

+2

在對象上有多個待處理的異步操作是很好的;只是指定同時調用對象是不安全的。如果套接口調用發生在處理程序之外,並且只有一個線程正在調用'io_service :: run()',則將套接字調用發佈到'io_service'中將會同步。促進。Asio要求調用者保證某些參數在調用處理程序之前保持有效;它從不強制用戶以特定方式管理它們。在某些情況下,通過智能指針將對象生命週期與異步鏈關聯可能會更容易。 –

相關問題