Boost::asio async_read 简单文件上传

Posted

技术标签:

【中文标题】Boost::asio async_read 简单文件上传【英文标题】:Boost::asio async_read simple file upload 【发布时间】:2019-11-30 17:36:15 【问题描述】:

我正在尝试使用 boost::asio 和 ajax 创建一个简单的文件上传。不知何故,即使我的缓冲区大小为 500MB,bytes_transferred 也达到了最大值 21845(或类似的值)。对于文本文件 std::cout 会显示一些内容,但对于二进制文件,它会在标题之后立即切断(仍然传输 21845 个字节)。

我尝试使用不同的方法,例如 async_read_some 和 async_read_until,但它没有改变任何东西。还尝试了使用 keep-alive 和更改套接字缓冲区大小的 socket.set_option()。

class tcp_connection

public:
void start() 
    boost::asio::async_read(socket, boost::asio::buffer(buf), boost::asio::transfer_at_least(1), boost::bind(&tcp_connection::handler, error, bytes_transferred));

private:
boost::array<unsigned char, 500000000> buf;
void handler(error, bytes) 
    std::cout << buf.data() << std::endl;

    boost::asio::async_write(socket, response_buffer, boost::bind(&tcp_connection, handler));


请查看https://pastebin.com/dPvVGsjU 以获取完整的最小可复制示例

我没有收到错误消息,尽管我忽略了 eof 错误。

【问题讨论】:

【参考方案1】:

为什么您认为在一次读取操作期间将读取整个数据?你的完成条件是transfer_at_least(1),所以读操作可以读取1、10、100或N个字节并返回。您应该读取数据,直到收到整个内容。因为不知道输入数据的长度,所以继续阅读直到出现eof

所以传入async_read的处理程序逻辑应该是:

void send_response2(const boost::system::error_code& err, const size_t& bytes) 

    if (err == boost::asio::error::eof)
    
        // analyze your buf2 here if it is what you wanted to read
        // here you can start sending data
    
    else if (err)
     /* problem */ 
    else 
    
        // call again async_read with send_response like
        boost::asio::async_read(socket, boost::asio::dynamic_buffer(buf2), boost::asio::transfer_at_least(1), boost::bind(&tcp_connection::send_response2, shared_from_this(),
                                                boost::asio::placeholders::error,
                                                boost::asio::placeholders::bytes_transferred));
    
   

您可以使用dynamic buffer 代替buffer::array 作为固定大小的缓冲区。然后通过添加新的读取字节来扩展您的缓冲区。

std::string buf2; // as data member
// then pass buffer by
boost::asio::dynamic_buffer(buf2)

【讨论】:

您好,非常感谢您的解决方案,但我试过了,似乎服务器根本没有发送任何响应。既然你写了 send_response2 你的意思是这是第二个处理程序还是直接在第一次读取操作之后?难道是浏览器没有发送eof? 基本上现在发生的事情是没有发送eof。相反,它会进行第二次读取操作,并且只等待至少 1 个字节,而这个字节永远不会到达。尝试使用 async_read_some 执行此操作,但也没有用。 读取数据的格式是什么?它是否有一些包含整个输入长度的标题? 当我上传 .png 时,它只显示 >PNG [o](想象一下二进制)。我猜那是PNG标头。浏览器发送的内容长度比 21845 大很多,但不发送 continue 标头。它不仅仅是二进制文件:当我上传一个长度超过 21845 的文本文件时,它会在 21845 字节处被截断。会不会和硬件有关? 此外,在上传 .png 等文件时,似乎根本没有调用处理程序 (send_response)。

以上是关于Boost::asio async_read 简单文件上传的主要内容,如果未能解决你的问题,请参考以下文章

Boost::asio::async_read 不会在条件下停止

boost::asio::async_read 不回调我的处理函数

优雅地取消 boost::asio::async_read

boost::asio::async_read 无限循环,接收数据为零字节

如何在到达终止字符时返回 boost::asio::async_read

boost asio async_read中的随机EOF