簡體   English   中英

在接收完整的Content-Length之前,boost :: asio :: async_read接收EOF

[英]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::bindstd::bind因為它們通常性能更高,例如允許編譯器內聯它們。 當然,除非您需要利用bind的動態特性。

暫無
暫無

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

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