2016-11-12 48 views
1

在Java和C#我用雙工插座通信以能夠由具有讀取從阻擋流傳入的數據包,和其他線程以同步的功能上發送分組的螺紋很容易寫雙向套接字通信。C++與ASIO

例如東西沿着線:

class MyBidirectionalSocket { 
    private OutputStream output; 

    public MyBidirectionalSocket(Socket socket) { 
     output = new BufferedOutputStream(socket.getOutputStream()); 
     new ReadingThread(socket).start(); 
    } 

    public synchronized void sendPacket(MyPacket packet) { 
     output.write(packet.getBytes()); 
     output.flush(); 
    } 

    private class ReadingThread extends Thread { 
     private InputStream input; 

     private ReadingThread(Socket socket) { 
      input = socket.getInputStream(); 
     } 

     public void run() { 
      // real code would catch EOF exceptions, IO exceptions, etc... 
      while (true) { 
       MyPacket packet = readPacketFromStream(input); 
       doSomethingWithPacket(packet); 
      } 
     } 
    } 
} 

總是工作很適合我,因爲我可以從輸入流只是讀數據,而不必費心當數據到達約實現readPacketFromStream - 它只是阻塞,直到數據可用,或者如果流被關閉,則拋出EOFException(或IOException),這可以在後面找到。如果我想要高吞吐量,我甚至可以沿着各種工作線程分發傳入數據包。

現在我的問題是 - 我希望做類似的事情,在C++中,具有跨平臺實現。但是如何?

我一直在學習Boost庫,因爲這些似乎得到廣泛的應用,有很多的功能。它們基本上提供了兩種與套接字進行通信的方式,一種是面向流的阻塞(使用套接字iostreams),另一種是使用異步套接字通信(Boost asio)。

阻塞方法似乎只工作半雙工,因爲iostream的不是線程安全的(這多線程應用程序可以和會寫,並在同一時間閱讀!)。因此,據我所知,這是沒有選擇的。

在我的情況下,異步方法似乎是最好的選擇。但是,我將收到大量的數據 - 可能包含數據包,半數據包或多個數據包,或其任何組合。 理想情況下,我會將接收到的數據存儲到流中,然後單獨的線程可以執行阻止讀取。

因此我的問題:

1)是否這樣的多線程「管道」流在C++中的存在,無論是在標準庫,以升壓,或其他地方?我當然不是世界上第一個需要這種東西的人,所以我懷疑它一定存在,儘管我找不到它。

2)可替換地,有另一種圖案 - 使用升壓或另一多平臺庫 - 可以被用於實現類似於上面的代碼的機制?

+1

你可以用'asio'做同步讀寫。爲了避免線程之間的任何種族問題,你可以使用'asio :: strand'。但是,你必須更好地瞭解'asio'才能實現這個想法。前往'asio'文檔並通過它的例子。 – Arunmu

+0

我跟着這些 - http://www.boost.org/doc/libs/1_62_0/doc/html/boost_asio/tutorial.html。儘管我明白你對種族問題的含義,但我仍然有將輸入數據「重構」爲可同步讀取的數據流的問題,並且從教程中不清楚如何處理該問題。 –

+0

我不認爲我理解「將傳入數據重構爲可同步讀取的數據流」。您的處理程序將對'asio :: socket'進行同步讀取,將其寫入'buffer',該文件可以是'array'或'string'或'asio :: streambuf'。您不必爲套接字創建單獨的「流」。將java程序行到行轉換爲C++沒有意義。這可能是非常低效的代碼。 – Arunmu

回答

0

boost :: asio非常靈活。您可以將它用於同步操作(阻塞直到數據發送或接收)或異步操作(您開始讀取/寫入操作並在完成後會在特定線程上進行回調)。您甚至可以將兩者混合使用,例如異步讀取並同步寫入。

如果你想按照你的Java模型儘可能靠近你可以簡單地粘到ASIO提供同步操作。

這意味着,如果你有一個像

shared_ptr<boost::asio::ip::tcp::socket> socket; 

插座時啓動一個額外的線程,使用阻塞讀取從那裏socket->read(...),可能寫入套接字從另一個線程與socket->write(...)。這是絕對安全的,只要你不做兩個併發讀取。對於併發寫入,您可能需要額外的互斥鎖。

請注意,這個同步寫入/讀取僅僅是一個非常小的包裝在本地OS套接字API的允許相同。 asios power主要是以異步變體的形式出現的(但是看起來不同於你的Java代碼,因此可能不太理想)。所以你甚至可以使用本地套接字。

關於ASIO上級包裝,ip::tcp::iostream stream: 可惜我也不知道這是否是線程安全與否,是否可以在相同的雙向配置被用作同步插座即可。但我會期待它,因爲否則對於大多數應用程序來說它將毫無價值。

+0

最後,我使用了異步方法,我編程將數據存儲在緩衝區中,直到收到完整的數據包。無論哪種方式,感謝您的意見,它證實了我不確定的事情,並且至少我處於瞭解我的選擇的階段。也感謝@Arunmu。 –