【问题标题】:C++ read()-ing from a socket to an ofstreamC++ read()-ing 从一个套接字到一个 ofstream
【发布时间】:2012-06-26 21:23:14
【问题描述】:

是否有 C/C++ 方法使用 read() 从套接字读取数据,并且接收缓冲区是文件(ofstream)或类似的自扩展对象(例如向量)?

编辑:当我考虑如何读取可能接收 10000+ 字节文件内容的流套接字时,问题出现了。我只是从来不喜欢将 20000 或 50000 字节(现在足够大)作为缓冲区放在堆栈上,文件可以在其中临时存储,直到我可以插入文件。为什么不直接将其流式传输到文件中以作为星标。

就像您可以在 std:string 中获取 char* 一样,我想到了类似的东西

read( int fd, outFile.front(), std::npos );  // npos = INT_MAX

或类似的东西。

结束编辑

谢谢。

【问题讨论】:

标签: c++ c sockets


【解决方案1】:

这很简单,而且我无法想象,但我认为按照这些思路可以解决问题:

template <unsigned BUF_SIZE>
struct Buffer {
    char buf_[BUF_SIZE];
    int len_;
    Buffer () : buf_(), len_(0) {}
    int read (int fd) {
        int r = read(fd, buf_ + len_, BUF_SIZE - len_);
        if (r > 0) len_ += r;
        return r;
    }
    int capacity () const { return BUF_SIZE - len_; }
}

template <unsigned BUF_SIZE>
struct BufferStream {
    typedef std::unique_ptr< Buffer<BUF_SIZE> > BufferPtr;
    std::vector<BufferPtr> stream_;
    BufferStream () : stream_(1, BufferPtr(new Buffer<BUF_SIZE>)) {}
    int read (int fd) {
        if ((*stream_.rbegin())->capacity() == 0)
            stream_.push_back(BufferPtr(new Buffer<BUF_SIZE>));
        return (*stream_.rbegin())->read(fd);
    }
};

在评论中,您提到您希望避免创建大的字符缓冲区。使用read 系统调用时,执行少量大读取通常比执行许多小读取更有效。因此,大多数实现都会选择大输入缓冲区来获得这种效率。你可以实现类似的东西:

std::vector<char> input;
char in;
int r;
while ((r = read(fd, &in, 1)) == 1) input.push_back(in);

但这将涉及系统调用和为每个输入字节复制至少一个字节。相比之下,我提出的代码避免了额外的数据副本。

我并不认为我发布的代码会成为您会采用的解决方案。我只是想为您提供一个说明,说明如何创建一个相当节省空间和时间的自扩展对象。根据您的目的,您可能想要扩展它,或编写自己的。在我的脑海中,一些改进可能是:

  • 请改用std::list,以避免调整矢量大小
  • 允许 API 一个参数来指定读取多少字节
  • 使用readv 始终允许一次读取至少BUF_SIZE 个字节(或超过BUF_SIZE 个字节)

【讨论】:

  • 有趣。我真正追求的是一种不必声明大字符缓冲区的方法。但是在 struct Buffer { char buf_[BUF_SIZE];... 你声明了一个 char 缓冲区。
  • @WesMiller:read 需要传递一个缓冲区,并且您希望将数据收集在一个自扩展数据结构中,这意味着在 read 返回之后存储缓冲区。如果您真的不希望在用户空间代码中创建缓冲区,那么您正在考虑创建自己的具有 0 复制语义的网络 I/O 设备驱动程序(直接访问内核使用的网络缓冲区)。
  • 好的,没那么远。对于接收到的数据流(它是一个流套接字)大小未知的情况,我考虑了自扩展对象。正如在上面的原始帖子中编辑的那样,我将收到一个未知大小的文件,并希望不必希望 char buffer[50000] “足够大”。保证不会迟早。
  • @WesMiller: BUF_SIZE 是允许调整缓冲区大小的模板参数。通常,它的大小应与输入的预期数据速率乘以读取调用之间的时间间隔相匹配。
【解决方案2】:

查看boost::asio 中的流支持。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-16
    • 1970-01-01
    • 2011-07-25
    • 1970-01-01
    • 2014-05-10
    • 2012-10-25
    • 2015-05-07
    相关资源
    最近更新 更多