首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >基于协议的C++软件设计

基于协议的C++软件设计
EN

Code Review用户
提问于 2013-06-12 10:02:07
回答 1查看 7.4K关注 0票数 6

我想要一个很好的设计来实现主从协议。该协议是专有的,类似于cctalk。我们有:

硕士:HEADER [ DATA ] CHECKSUM

从:HEADER [ DATA ] CHECKSUM

我的选择是为请求和响应设置具体的基类:

代码语言:javascript
复制
class PacketReq {
public:
    typedef std::vector<uint8_t>       container;
    typedef container::const_iterator  const_iterator;

    PacketCommand command() const
    {
        return static_cast< PacketCommand >( mBuffer[ 2 ] );
    };

    const container& data() const
    {
        return mBuffer;
    }

    const_iterator begin() const
    {
        return mBuffer.begin();
    }

    const_iterator end() const
    {
        return mBuffer.end();
    }

protected:
    container mBuffer;
};

class PacketOut1 : public PacketReq {
public:
    PacketOut1()
    {
        mBuffer.reserve( PacketHeaderHelper::HEADER_SIZE );
        mBuffer.push_back( /* something. */ );
        mBuffer.push_back( /* something. */ );
        mBuffer.push_back( /* something. */ );
        mBuffer.push_back( /* something. */ );
    }
};

响应可以是好的响应,也可以是NACK (错误)。我的恳求是:

代码语言:javascript
复制
class PacketRes {
public:
    PacketRes(const std::vector<uint8_t>& buffer) 
    {
        if (!checkChecksum( buffer ))
        {
            throw Error("invalid checksum");
        }

        PacketHeaderHelper header( buffer );
        mCommand = header.command();

        if (header.len() > PacketHeaderHelper::HEADER_SIZE)
        {
            const size_t bodySize = header.len() - PacketHeaderHelper::HEADER_SIZE;

            mData.reserve( bodySize );

            mData.insert(
                mData.end(),
                buffer.begin() + PacketHeaderHelper::HEADER_SIZE - 1,
                buffer.end() - 1
                );
        }        
    }

    virtual ~PacketReq() {}

    PacketCommand command() const
    {
        return mCommand;
    }    

    const std::vector<uint8_t>& body() const
    {
        return mData;
    }

private:
    bool checkChecksum(const std::vector<uint8_t>& buffer) const
    {
        /* calc checksum. */
    }

private:
    std::vector<uint8_t> mData;
    PacketCommand mCommand;
};

class PacketInAck : public PacketReq {
public:
    PacketInAck(const std::vector<uint8_t>& buffer) : PacketReq( buffer )
    {
    }
};

因此,如果我想提出请求,那么顺序是:

代码语言:javascript
复制
lock_guard 
send( const PacketOut& p ) 
std::unique_ptr< PacketRes > read();

但我不喜欢这个设计,但效果很好。

还有其他方法来实现这一点吗?

EN

回答 1

Code Review用户

回答已采纳

发布于 2013-06-14 14:22:39

一个可能的预测执行可以是以下几个方面:

所有的包都没有继承,没有接收的包,也没有发送的包。

PacketOutAPacketOutBPacketOutC都是具有公共接口的类,它们只有两种方法:begin()end()来访问内部数据;

接收类有PacketInAPacketInB等。

Communication用于允许我向通信端口发送和接收数据。

ReaderAndValidator类允许我获取并验证接收数据包的主体。

Dispatcher类允许我从接收到的邮件中获取一个包(对不起,我的英语.看这个例子..。)

相反,需要使用Device类在域上下文中快速显示我们连接的设备。

代码语言:javascript
复制
/** abstract the communication mechanism. */
class Communication {
public:

    Communication ();

    template < typename Iterator >
    void send( Iterator first, Iterator last ) const
    {
        // send from first to last to 
    }

    template< typename Iterator >
    std::vector< char > read( Iterator first, Iterator last ) const
    {
        // read from first to last to 
    }

private:
    // internal stuff
};

/** Validate an input packet and get the body */
class ReaderAndValidator {
public:

    ReaderAndValidator ( const Communication& comm )
        : mComm( comm )
    {
    }

    std::vector< char > read()
    {
        // read data
        return mComm.read( /* params */ );
    }

private:
    const Communication& mComm;
}

/** Given the PacketOut obtain the corrisponding PacketIn. */
template < typename PacketOut >
class Dispatcher {
    Dispatcher()
    {
        static_assert( false, "unable to instantiate Controller" );
    }
};

template <>
class Dispatcher< PacketOutA > {
public:
    Dispatcher( const Communication& comm )
        : mComm( comm )
    {
    }

    PacketInA send( const PacketOutA & packet ) const
    {
        mComm.send( std::begin( packet ), std::end( packet ) );

        ReaderAndValidator reader( mComm );
        auto body = reader.read();

        // RVO
        PacketInA result( std::begin( body ), std::end( body ) );
        return result;
    }

private:
    const Communication& mComm;
};

// same thing for Controller< PacketOutB >, Controller< PacketOutC > and so on


class Device : private boost::noncopyable {
public:

    Device ()
    {
        // init communication
    }

    void doPacketOutA( int param )
    {
        PacketOutA packet( param );
        recieve( packet );
    }

    PacketInB doPacketB()
    {
        PacketOutB packet();
        return recieve( packet );
    }

private:

    template < typename PacketOutKind >
    auto recieve( const PacketOutKind& p ) -> decltype( std::declval< Dispatcher< PacketOutKind > >().send( p ) ) )
    {
        Dispatcher< PacketOutKind > disp( mCommunication );
        return controller.send( p );
    }

private:

    Communication mCommunication;
};
票数 3
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/27297

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档