[英]boost::asio::async_read receiving EOF before receiving the complete Content-Length
我正在使用Boost ASIO實現HTTP文件下載客戶端。 我正在使用async_read操作。 我面臨的問題是在接收完整內容(即Content-Length)之前我正在接收EOF的async_read,這與內容大小無關。 鑒於我的閱讀操作
void Http::ResumableAsyncDownload::read_content(const boost::system::error_code& err, size_t _size)
{
try {
if ( !err)
{
received_bytes += _size;
if ( ofs_.is_open() ) {
// Write all of the data that has been read so far.
ofs_ << &response_;
} else {
ofs_.open(std::string(params_.tempdir + "/" + params_.partnumber).c_str());
if ( ofs_.is_open() ) {
ofs_ << &response_;
} else {
DEBUG_MSG("Error while opening file to store downloaded data. File Path = %s\n", std::string(params_.tempdir + "/" + params_.partnumber).c_str());
std::cout << ("Unable to open local file for storing downloaded data");
}
}
// Continue reading remaining data until EOF.
boost::asio::async_read(*ssocket_, response_,
boost::asio::transfer_at_least(1),
boost::bind(&ResumableAsyncDownload::read_content, this, _1, _2)
);
}
else if (err != boost::asio::error::eof)
{
DEBUG_MSG("[NET] : Exception in ResumableAsyncDownload in read_content : %s\n", err.message().c_str());
std::cout << ("Asynchronous File Download Error: " + err.message());
}
if(err == boost::asio::error::eof)
{
std::cout << "[RESPONSE] : EOF: We are not breaking connection\n";
ssocket_->shutdown();
delete ssocket_;
ssocket_ = NULL;
delete ctx;
ctx = NULL;
if ( (content_length != received_bytes) && !(params_.get_size) ) {
std::cout << "Failed to receive complete data packet. Content Length = " << content_length << " Received Bytes = " << received_bytes << std::endl;
// ofs_.clear();
}
}
} catch ( std::exception &ex ) {
std::cout << "We have an exception. Exception = " << std::string(ex.what()) << std::endl;
}
}
例如,Content-Length為292309324,但是我將在292309324之前收到EOF。
為了解決這個問題,我使用HTTP Range標頭實現了Chunked下載,但是在這種情況下,對於我請求的每個塊,我收到的數據都少於所請求的塊,然后我重新計算下一個范圍,它在最后一個塊之前起作用。 我從來沒有收到最后一塊,通常情況是
Range for last chunk 227376464-227376641/227376641
Requested Bytes = 178
響應標題
X-Powered-By: Undertow/1
Content-Range: bytes 227376464-227376641/227376641
Server: WildFly/9
Content-Length: 178
Accept-Ranges: bytes
OperationId: 4a847024-2348-42bd-af7d-3638e41cba4f
Date: Thu, 17 Aug 2017 11:41:18 GMT
Set-Cookie: SERVERID=04-84FRD2128G0US; path=/
Cache-control: private
如您所見,服務器以最后一個塊的良好范圍進行響應,但在read_content中卻給出了EOF。
因此,在兩種方法中,read_content都不讀取完整的數據並給出EOF。 據我了解,EOF是服務器關閉的套接字,也可能導致短讀,但不是我的分塊下載解決方案。 我不應該完整收到最后一個分塊的數據包。
對出什么問題有什么想法嗎? 另請注意,我正在調用自定義API來下載文件,但是即使我從某個公共鏈接(即http://mirror.pnl.gov/releases/16.04/ubuntu-16.04.3)下載,也會遇到相同的問題-desktop-amd64.iso ),因此我認為問題不在我的服務器端。 另請注意,如果我使用boost :: asio :: async_read的同步版本(即boost :: asio :: read),則不會看到此問題。 我正在使用為ARM編譯的Boost 1.55版本。
我建議在您的Http
類中添加一個總字節數計數器size_t bytes_transferred_total_;
並放棄err == boost::asio::error::eof
。 您知道總大小,因為它是您解析的原始HTTP標頭Content-Length: <total_body_size>
一部分。 修改后的代碼如下所示:
...
if (!err) {
received_bytes += _size;
bytes_transferred_total_ += _size;
...
} else {
...
}
boost::asio::async_read(
*ssocket_, response_, boost::asio::transfer_at_least(1),
boost::bind(&ResumableAsyncDownload::read_content, this, _1, _2));
// continue reading until all data has been received
if (bytes_transferred_total_ >= content_length_from_header_) {
// you've received it all
}
在初始化content_length_from_header_
確保您理解它表示主體本身的大小,但不包括標題。
腳注:考慮使用lambda而不是boost::bind
或std::bind
因為它們通常性能更高,例如允許編譯器內聯它們。 當然,除非您需要利用bind
的動態特性。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.