我目前正在使用Boost Asio實現一個網絡協議。域類已經存在,並且我能夠連續兩次調用boost :: asio :: read檢索正確的數據
- 寫入數據包發送到
std::istream
- 和讀取從
std::ostream
包。
甲網絡分組包含網絡分組報頭。頭部以數據包長度字段開頭,其字段大小爲兩個字節(std::uint16_t
)。
我使用TCP/IPv4的作爲傳輸層,因此我嘗試執行以下操作:
- 讀取數據包的長度,以瞭解它的總長度。這意味着只需從套接字讀取兩個字節。
- 閱讀數據包的其餘部分。這意味着從套接字準確讀取
kActualPacketLength - sizeof(PacketLengthFieldType)
個字節。 - Concat都讀取二進制數據。
因此,我需要至少兩個電話boost::asio::read
(我開始同步!)。
我能有一個調用來讀取數據包到boost::asio::read
如果我硬編碼期望的長度:
Packet const ReadPacketFromSocket() {
boost::asio::streambuf stream_buffer;
boost::asio::streambuf::mutable_buffers_type buffer{
stream_buffer.prepare(Packet::KRecommendedMaximumSize)};
std::size_t const kBytesTransferred{boost::asio::read(
this->socket_,
buffer,
// TODO: Remove hard-coded value.
boost::asio::transfer_exactly(21))};
stream_buffer.commit(kBytesTransferred);
std::istream input_stream(&stream_buffer);
PacketReader const kPacketReader{MessageReader::GetInstance()};
return kPacketReader.Read(input_stream);
}
這讀取一次完整的分組數據並返回Packet
實例。這是有效的,所以這個概念正在起作用。
到目前爲止這麼好。現在我的問題:
如果我連續撥打boost::asio::read
與boost::asio::streambuf
我不能得到它的工作。
下面是代碼:
Packet const ReadPacketFromSocket() {
std::uint16_t constexpr kPacketLengthFieldSize{2};
boost::asio::streambuf stream_buffer;
boost::asio::streambuf::mutable_buffers_type buffer{
stream_buffer.prepare(Packet::KRecommendedMaximumSize)};
std::size_t const kBytesTransferred{boost::asio::read(
// The stream from which the data is to be read.
this->socket_,
// One or more buffers into which the data will be read.
buffer,
// The function object to be called to determine whether the read
// operation is complete.
boost::asio::transfer_exactly(kPacketLengthFieldSize))};
// The received data is "committed" (moved) from the output sequence to the
// input sequence.
stream_buffer.commit(kBytesTransferred);
BOOST_LOG_TRIVIAL(debug) << "bytes transferred: " << kBytesTransferred;
BOOST_LOG_TRIVIAL(debug) << "size of stream_buffer: " << stream_buffer.size();
std::uint16_t packet_size;
// This does seem to modify the streambuf!
std::istream istream(&stream_buffer);
istream.read(reinterpret_cast<char *>(&packet_size), sizeof(packet_size));
BOOST_LOG_TRIVIAL(debug) << "size of stream_buffer: " << stream_buffer.size();
BOOST_LOG_TRIVIAL(debug) << "data of stream_buffer: " << std::to_string(packet_size);
std::size_t const kBytesTransferred2{
boost::asio::read(
this->socket_,
buffer,
boost::asio::transfer_exactly(packet_size - kPacketLengthFieldSize))};
stream_buffer.commit(kBytesTransferred2);
BOOST_LOG_TRIVIAL(debug) << "bytes transferred: " << kBytesTransferred2;
BOOST_LOG_TRIVIAL(debug) << "size of stream_buffer: " << stream_buffer.size();
// Create an input stream with the data from the stream buffer.
std::istream input_stream(&stream_buffer);
PacketReader const kPacketReader{MessageReader::GetInstance()};
return kPacketReader.Read(input_stream);
}
我有以下問題:
- 讀取來自
boost::asio::streambuf
數據包長度的第一插槽讀取似乎從boost::asio::streambuf
刪除數據之後。 - 如果我使用兩個截然不同的
boost::asio::streambuf
實例,我不知道如何「連接」/「追加」它們。
在一天結束時,我需要一個std::istream
與從套接字獲得正確的數據。
有人可以引導我進入正確的方向嗎?我試圖讓這項工作現在幾個小時...
也許這種方法不是最好的,所以我願意提出改進我的設計的建議。
謝謝!
你確定你的代碼編譯?我無法讓它與GCC 4.7.1和Boost 1.55.0一起工作。我還喜歡使用一個'streambuf'作爲我的例子。 –
我打錯了'ostream' :)當然你可以有一個r/w流(記得在適當的時候尋找原點) – sehe
你能詳細說明嗎?我確實需要一個'std :: istream'對象將它傳遞給我的PacketReader。另一個問題是,如果我從中讀取數據包的長度,第一個'streambuf'就會被修改。是不是可以使用** 1 **'streambuf'來讀取兩個套接字(並從中讀取'streambuf'),以便通過第二次讀取附加'streambuf'? –