使用basic_stringstream序列化对象(如std :: wstring)以通过TCP传输

时间:2016-03-21 14:05:45

标签: c++ buffer stringstream

我正在使用网络信使来通过TCP / IP发送和接收Message个对象。通常,消息包含基元std::string;或者字符串向量但是,有些情况下我需要发送UTF16 Unicode std::wstring

据我所知,从TCP的角度来看,无论如何,所有内容都将被转换为字节数组(char),因此应该可以按字节顺序发送这些wstring。在接收和反序列化之后,我强制将数据转换为其在标题中声明的相应messageType。

消息如下所示:

class ConcreteMessage: public Message
{
private:  
    std::wstring m_myString;
    int aPrimiteVariable;

public:
    // serializes the messages variables and sends it to the MemoryStream
    void save(util::MemoryStream& out)
    {
         out << aPrimiteVariable;

         size_t len = m_myString.size();      // length of the string (number of wchar_t's)
         out << len;

         size_t sz = m_myString.size() * sizeof(wchar_t);    // effective size of the string (len * 2 bytes on Windows)
         out << sz;

         /// send the wstring to the MemoryStream             
         if (sz)
            out.write((const unsigned char*)m_myString.c_str(), sz);

    }

    /// does the same thing in reverse to deserialize the message. Must be done in the exact same order!
    void load(util::MemoryStream& in)
    {
       in > aPrimiteVariable;

       size_t len;
       in >> len;
       m_myString.resize(len);

       size_t sz;
       in >> sz;

       if (sz)
          in.read((unsigned char*)&m_myString.front(), sz);
    }
};

我使用扩展basic_stringstream进行解/序列化:

#pragma once

#include <sstream>

namespace util {

class MemoryStream : public std::basic_stringstream<unsigned char>
{
    typedef std::basic_stringstream<unsigned char> TBase;

public:
    MemoryStream()
    {
    }

    MemoryStream(const unsigned char* begin_, const unsigned char* end_)
    : TBase(std::basic_string<unsigned char>(begin_, end_))
    {
    }

    template<typename T>
    MemoryStream& operator <<(T i) {
        return writePrimitive(i);
    }

    template<typename T>
    MemoryStream& operator >>(T& i) {
        return readPrimitive(i);
    }

    template<typename T>
    MemoryStream& operator <<(std::basic_string<T> s) {
        size_t len = s.length();
        writePrimitive(len);
        write(reinterpret_cast<const unsigned char*>(s.c_str()), len * sizeof(T));
    }

    template<typename T>
    MemoryStream& operator >>(std::basic_string<T>& s) {
        size_t len = 0;
        readPrimitive(len);

        util::ScopedArray<T> buf(new T[len + 1]);
        memset(buf.get(), 0, (len + 1) * sizeof(T));

        read(reinterpret_cast<unsigned char*>(buf.get()), len * sizeof(T));

        s = buf.get();
    }

private:

    template<typename T>
    MemoryStream& writePrimitive(T t)
    {
        write(reinterpret_cast<const unsigned char*>(&t), sizeof(t));
        return *this;
    }

    template<typename T>
    MemoryStream& readPrimitive(T& t)
    {
        read(reinterpret_cast<unsigned char*>(&t), sizeof(t));
        return *this;
    }
};

template<typename T>
inline
MemoryStream& operator <<(MemoryStream& st, T t)
{
    return st.operator <<(t);
}

template<typename T>
inline
MemoryStream& operator >>(MemoryStream& st, T& t)
{
    return st.operator >>(t);
}

} 

请注意,此类继承std::basic_stringstream<unsigned char>而非wchar_t

现在,在接收此类数据时,我需要将其转换为相应的消息类:

if (ConcreteMessage* msg = dynamic_cast<ConcreteMessage*>(m))
// etc....

首先:到目前为止一切顺利(令人惊讶)。但是,有大量的reinterpret_castdynamic_cast s,它感觉有点脏。

你认为这种方法有什么严重的问题吗?

我总是听说你永远不应该使用reinterpret_cast和&#39; dynamic_cast&#39;,但是在分布式系统上进行这样的序列化处理时,有没有办法避免它们? / p>

0 个答案:

没有答案