如何最好地从其他类访问网络功能?

时间:2017-11-24 05:16:41

标签: c++ boost-asio

C ++新手。

我正在尝试通过一个项目来教自己C ++来创建一个从远程服务器获取命令并将遥测发送回远程服务器的机器人。

我在Robot上有一个TcpCom类,它包含套接字连接和公共函数,用于从服务器发送消息和接收消息:

#ifndef TCPCOM_H
#define TCPCOM_H
#define BOOST_DATE_TIME_NO_LIB
#include <boost/asio.hpp>
#include <boost/interprocess/sync/interprocess_semaphore.hpp>
#include <deque>
#include <mutex>
#include "COM.h"

class TcpCom : public COM
{

    public:
        TcpCom() : io_srv(), tcpSocket(io_srv), remoteHost(""), remotePort(""), connectedToRemoteHost(false), outboundMsgQueue(), outboundMsgQueueMutex(),
        messagesInOutboundMsgQueue(0), incomingMsgQueue(), incomingMsgQueueMutex()
        {}
        int initialize();
        void connectToRemoteHost(const std::string host, const std::string port);
        void disconnectFromRemoteHost();
        bool messagesWaitingInIncomingMsgQueue();
        SoftwareBusMsg getMsgFromIncomingMsgQueue();
        void addMsgToOutboundMsgQueue(SoftwareBusMsg& sbMsg);
        bool isConnected();

    private:
        void writeOutboundMsgToSocket();
        void deserializeHeader(std::string headerStr, MsgHeader& msgHdr);
        void addMessageToIncomingMsgQueue(SoftwareBusMsg& sbMsg);
        void readIncomingMsgHeader(MsgHeader& msgHdr);
        std::string readIncomingMsgData(uint32_t msgDataLength);
        SoftwareBusMsg readMsgFromSocket();
        void incomingMsgThread();
        void outboundMsgThread();
        void startReadAndWriteThreads();

        boost::asio::io_service io_srv;
        boost::asio::ip::tcp::socket tcpSocket;
        std::string remoteHost;
        std::string remotePort;
        bool connectedToRemoteHost;

        std::deque<std::string> outboundMsgQueue;
        std::mutex outboundMsgQueueMutex;
        boost::interprocess::interprocess_semaphore messagesInOutboundMsgQueue;

        std::deque<SoftwareBusMsg> incomingMsgQueue;
        std::mutex incomingMsgQueueMutex;
        //boost::interprocess::interprocess_semaphore messagesInIncomingMsgQueue;

};
#endif

我希望其他类(例如负责电机控制的类)能够将消息发送到服务器以进行遥测/错误报告。我可能在这里错了,但似乎将TcpCom类的实例直接传递给需要能够向服务器发送消息的每个类都是不好的设计。

相反,我尝试创建一个EventReporter类,其中包含一个私有成员,该成员是对TcpCom类的引用。这将允许封装用于处理不同类型事件(信息,错误)的代码,并且我可以将初始化的“EventReporter”对象传递给需要它的所有内容。

#include "TcpCom.hpp"

class EventReporter
{
    public:
        EventReporter(TcpCom& tcpComIn) : tcpCom(tcpComIn)
        {}
        //Will contain call to tcpCom.addMsgToOutboundMsgQueue()
        void reportEvent(std::string eventType, std::string message);
    private:
        TcpCom tcpCom;
};

当我尝试编译此代码时,我遇到了一些错误:

error: use of deleted function 'TcpCom::TcpCom(const TcpCom&)'

error: use of deleted function 'boost::asio::io_service(const boost::asio::io_service&)'

看起来我的新班级试图制作TcpCom的副本,我认为我通过引用将其传递给了我。

我应该使用类似unique_ptr的内容来避免复制TcpCom,还是有更好的方法可以从其他类访问网络功能?

谢谢!

1 个答案:

答案 0 :(得分:1)

抛出是回答这个问题还是作为拼写错误关闭,所以我会发帖并让问题的Asker告诉我。

class EventReporter
{
    public:
        EventReporter(TcpCom& tcpComIn) : tcpCom(tcpComIn)
        {}
        //Will contain call to tcpCom.addMsgToOutboundMsgQueue()
        void reportEvent(std::string eventType, std::string message);
    private:
        TcpCom tcpCom; //<- this is not a reference
};

TcpCom tcpCom;定义了一个TcpCom的实例,而不是像Asker所说的那样TcpCom的引用,所以成员初始化列表中的tcpCom(tcpComIn)(对它们很好)顺便说一句,使用列表。许多认为不再学习的C ++程序员似乎并不知道他们存在了)执行副本他们试图通过在参数列表中通过引用来避免。

错误消息来自TcpCom成员不可复制的成员(至少是std :: mutex。互斥锁的多个副本会很糟糕),因此即使您想要也不能复制一个。

简单的解决方案是

class EventReporter
{
    public:
        EventReporter(TcpCom& tcpComIn) : tcpCom(tcpComIn)
        {}
        //Will contain call to tcpCom.addMsgToOutboundMsgQueue()
        void reportEvent(std::string eventType, std::string message);
    private:
        TcpCom & tcpCom; //<- change made here
};

除非Asker还将其他不可复制的对象复制到其他代码中,否则EventReporter实例可能比源TcpCom更长,所以它们应该是好的。