簡體   English   中英

使用streambuf中的boost :: asio :: ip :: tcp將數據部分寫入TCP套接字

[英]Writing sections of data to TCP socket with boost::asio::ip::tcp from streambuf

對於那些向下投票的注意事項:這個問題不是關於asio的異步方面(雖然也許異步解決方案在這里可能有意義,這是我最后提出的一個問題)。 這實際上就是使用帶有asio tcp套接字包裝的streambuf和ostreams。 示例/教程未涵蓋此特定方面(對寫入調用進行細分)。

我正在為一個插件環境編寫一些(希望很簡單的)代碼,該環境需要向外部服務器發送相當大的數據塊(~2MB)以響應某些事件。 數據需要相當迅速,完整地發送,但它並不常見,我並不過分關注原始性能。 我正在使用Google的Protocol Buffers來序列化數據。

截至目前,我有以下代碼幾乎可以工作:

#include <boost/asio.hpp>

// connect to the server:
boost::asio::io_service io_service;
tcp::resolver resolver(io_service);
tcp::resolver::query query(server_address, server_port);
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
tcp::socket socket(io_service);
boost::asio::connect(socket, endpoint_iterator);

// float_array consists of ~500,000 floats in a ProtoBuf message:
//
// message FloatArray {
//   repeated float data = 1 [packed=true];
// }

// send the serialized float_array to the server:
boost::asio::streambuf b;
std::ostream os(&b);
float_array.SerializeToOstream(&os);
boost::asio::write(socket, b);

// the TCP connection *must* now close to signal the server

這個問題是我正在工作的環境(多線程)看到write()操作花費太長時間(它阻塞),並終止線程。 由於我不允許創建自己的線程,我需要將write()操作拆分為多個單獨的寫入。

我關心的是如何做到這一點。 我知道我可以使用它來發送確切的字節數:

boost::asio::write(socket, b, boost::asio::transfer_exactly(65536));

但正確地說,我需要確切地知道ostream中剩余的字節數。 我注意到b.size()會相應減少,所以我可以使用它。 但是為了分割我的寫入,我需要在調用此函數之間存儲一些狀態。

我有一個選擇是在調用我的寫入函數之間存儲streambuf b和ostream os,但我想知道是否有更好的方法來執行此操作。 據我所知,部分序列化ProtoBuf輸出是不可能的,所以我認為我對一次調用float_array.SerializeToOstream() 那么問題是,是否有一種正確的方法可以直接查詢ostream的可用字節數,或者可能使用其他一些機制( boost::asio::buffer可能?)。

我很高興自己回顧一下boost :: asio文檔,我只是想找一些關於如何繼續的指導,因為有很多文檔需要解決,我不確定這個難題的哪個部分是相關的。

一個想法 - 是否可以使用boost :: asio沿着這些線創建某種單線程異步“發送者”,可以為我處理這種狀態? 例如,我可以調用某種非阻塞的write()函數,然后使用某種回調(或經常訪問的函數)來檢查完成情況,然后關閉TCP連接嗎?

雖然我無法找到一種方法來查詢ostream來直接確定流中“等待”的數據量,但我能夠完全避免使用ostream並將數據序列化為char*數組。 然后可以使用boost::asio::write()函數以類似於舊式C套接字方法的方式發送它:

...
tcp::socket socket(io_service);
char * buffer = new char[size];  // or a smart-ptr
float_array.SerializeToArray(static_cast<void*>(buffer, size));
void * p = static_cast<void*>(buffer);
int bytes_sent = boost::asio::write(socket, boost::asio::buffer(p, bytes_to_send);

或者,如果首選使用boost::asio::streambufstd::ostream ,那么在使用ostream寫入一些數據后,似乎可以查詢streambuf(使用.size() ):

boost::asio::streambuf b;
std::ostream os(&b);
float_array.SerializeToOstream(&os);

// send a chunk of a particular size
int bytes_to_send = std::min(chunk_size, b.size());
cout << b.size() << endl;  // shows amount of remaining data
boost::asio::write(socket, b, boost::asio::transfer_exactly(bytes_to_send));
cout << b.size() << endl;  // shows a reduction in amount of remaining data

因此,如果多次調用(對於每個塊),則需要將ostream,streambuf和io_service保留在范圍內。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM