BOOST Asio:async_write_some与async_write选型及单写操作需求
解决方案
你的思路完全没问题,针对FunctionFS这类有单次写入语义要求的特殊文件,确实不能用asio::async_write,直接使用async_write_some的核心需求是可行的。
核心原理
Asio的posix::basic_stream_descriptor::async_write_some在处理缓冲区序列时,本质上是直接将整个序列传递给底层的writev(分散写)系统调用,不会主动拆分缓冲区序列去发起多次系统调用。只有当内核因资源限制等原因返回部分写入时,async_write_some才会返回实际写入的字节数——这完全符合你要的“仅当系统调用决定时才写入更少数据”的要求。
处理部分写入的场景
直接调用async_write_some可能出现数据未完全写入的情况,这时候需要你手动处理剩余数据的写入,但必须保证每次剩余数据的写入都作为独立的async_write_some调用,这样才能维持单次写入对应单次系统调用的语义。
以下是一个实现示例:
#include <asio/posix/basic_stream_descriptor.hpp> #include <vector> using namespace asio; void do_write(posix::basic_stream_descriptor<>& stream, std::vector<const_buffer> buffers, std::size_t total_bytes) { stream.async_write_some(buffers, [&stream, buffers, total_bytes](std::error_code ec, std::size_t written) { if (ec) { // 这里处理写入错误,比如打印日志、触发错误回调等 return; } if (written < total_bytes) { // 整理剩余的缓冲区,跳过已写入的部分 auto buf_iter = buffer_sequence_begin(buffers); std::size_t skipped_bytes = 0; // 跳过已经完全写入的缓冲区 while (skipped_bytes + buffer_size(*buf_iter) <= written) { skipped_bytes += buffer_size(*buf_iter); ++buf_iter; } std::vector<const_buffer> remaining_buffers; // 如果当前缓冲区有部分数据未写入,截取剩余部分 if (skipped_bytes < written) { const auto& current_buf = *buf_iter; auto remaining_in_current = buffer_size(current_buf) - (written - skipped_bytes); remaining_buffers.emplace_back( static_cast<const char*>(buffer_cast<const void*>(current_buf)) + (written - skipped_bytes), remaining_in_current ); ++buf_iter; } // 添加剩下的完整缓冲区 remaining_buffers.insert(remaining_buffers.end(), buf_iter, buffer_sequence_end(buffers)); // 发起下一次独立的写入调用 do_write(stream, remaining_buffers, total_bytes - written); } else { // 全部数据写入完成,处理后续逻辑 } }); }
为什么不能用asio::async_write
asio::async_write的设计逻辑是自动多次调用async_write_some,直到所有数据被写入完成——这会导致多次系统调用,而多次调用会被FunctionFS解析为多个独立的USB传输,破坏你需要的“单次写入对应单个USB传输”的语义,所以你的选择是正确的。
内容的提问来源于stack exchange,提问作者Johannes Schaub - litb
相关产品推荐
相关产品推荐

