【问题标题】:looking for a MemoryStream in C++在 C++ 中寻找 MemoryStream
【发布时间】:2011-03-06 16:34:43
【问题描述】:

在美妙的 C# 世界中,我可以创建内存流而无需指定其大小, 写入它,然后只取底层缓冲区。

我如何在 C++ 中做同样的事情?基本上我需要做的:

memory_stream  ms(GROW_AS_MUCH_AS_YOU_LIKE);

ms << someLargeObjects << someSmallObjects << someObjectsWhosSizeIDontKnow;

unsigned char* buffer = ms.GetBuffer();
int bufferSize = ms.GetBufferSize();

rawNetworkSocket.Send(buffer, bufferSize);

顺便说一下,虽然我对项目不太熟悉,但我在项目中得到了提升。

谢谢。

【问题讨论】:

  • @Martin:我不,我想创建一个流,填充它,获取底层缓冲区,然后发送它。我也不能使用 boost::socket,我在 WINSOCK API 上使用服装协议,所以我只能发送整个缓冲区。

标签: c++ boost stl stream buffer


【解决方案1】:
#include <sstream>

std::ostringstream  buffer; // no growth specification necessary
buffer << "a char buffer" << customObject << someOtherObject;

std::string contents = buffer.str();
size_t bufferSize = contents.size();

rawNetworkSocket.Send(contents); // you can take the size in Send

使用这种方法,您必须在收到结果的地方解析结果(因为上面的代码只是将您的数据转换为非结构化字符串。

另一个问题是,由于 C++ 不支持反射,你必须为你的对象定义操作符 Custom 类的代码:

template<typename C, typename T>
std::basic_ostream<C,T>& operator << (
    std::basic_ostream<C,T>& out, const Custom& object)
{
    out << object.member1 << "," << object.member2 /* ... */ << object.memberN;
    return out;
}

如果您想要结构化序列化,请查看boost::serialization。

【讨论】:

    【解决方案2】:

    在 Boost 方面,Iostreams 非常相似。

    【讨论】:

      【解决方案3】:

      由于您在谈论网络,因此您似乎非常想创建某种消息并通过网络发送。

      有一些库可以创建消息并为这些消息生成 API,最著名的是 Google Protocol Buffers(简称protobuf)。它让您可以在一个短文件(自定义格式)中描述您的消息的语法,然后自动生成 API 以在 C++/Python/Java 中解码此消息

      优势包括:

      • 互操作性,这也意味着可以在此处使用脚本语言检查消息,在调试时很方便。
      • 版本处理(向后和向前兼容性),因为我们知道您很快会修改消息,但可能不会立即升级所有内容
      • 文本/二进制输出。文本便于调试,每个位都需要二进制

      此外,还可以使用文本输出并使用 LZO 等压缩它以获得一些空间:)

      【讨论】:

      • 那太好了,但是我已经有一个用于传递消息的自定义协议和 API,我的消息将在 xml 中,我的客户端是 C#... 我想做什么是使用 boost::serialization 将我的消息传输到 xml,获取生成的流获取缓冲区并按原样发送到 C# 端
      • 不要为此使用序列化。它将两个独立的实体联系在一起。您可以完美地为 Google 编写一个 C# API 生成器(考虑到他们与微软的战争,他们不太可能自己做)。或使用其他消息传递方案。但是序列化意味着相同的二进制文件来解码对象,如果您有一个对象的单个字段,那么您必须立即更新 C# 端,否则它就会停止工作......并且您必须在 C# 端具有相同的模型太:这是一个维护地狱。你需要定义一个正式的接口(xml,如果你必须:/或json等......)。
      【解决方案4】:

      为此,您可能需要查看std::stringstream。流将根据需要增长。除非您想将对象保留为二进制而不是 ASCII,在这种情况下,您可以查看 streambuf 对象和实现。

      请注意,C++ 没有反射或双重/多重分派,因此您必须自己为未知大小的对象提供支持:

      class unknown_base {
         virtual void dump( std::ostream & ) const;
      };
      std::ostream& operator<<( std::ostream& o, unknown_base const & obj ) {
         obj.dump( o );
         return o;
      }
      std::string serialize( std::vector<unknown_base*> const & data ) {
         std::ostringstream st;
         for ( std::vector<unknown_base*>::const_iterator it = data.begin(), end = data.end();
               it != end; ++it ) {
            st << **it; // double dereference: iterator, pointer
         }
         return st.str();
      }
      

      【讨论】:

      • 为什么std::stringstream 不适用于二进制对象?它可以在任何事情上工作。只需写或 std::string 对象,它可以包含任何东西,包括0(C 字符串终止字符),在@987654326 中间没有相同的含义@,
      • @Didier 约定是操作员
      • @Pete:你也可以使用std::stringstream的write()成员函数。
      • 如果您使用ostream 打印支持operator&lt;&lt; 的库中的基本类型或类型,那么它将以人类可读的形式编写。我不应该说 ASCII,而是人类可读的。
      猜你喜欢
      • 1970-01-01
      • 2011-07-12
      • 2018-05-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-15
      • 2017-08-17
      相关资源
      最近更新 更多