Cocoa开发——PIPE通讯框架

Cocoa开发——PIPE通讯框架,第1张

概述进程通讯方式有很多种,OSX系统的进程通讯方式更是多种多样,笔者暂时只写过XPC和有名管道通讯的框架,特此记录一下自己的心得。 首先基于Pipe有名管道的进程通讯,我们将管道创建,打开,读取,写入等 *** 作封装到CPipeWrapper的类中,方便对管道的一系列 *** 作。 class CPipeWrapper{public: CPipeWrapper(); ~CPipeWrapper(

进程通讯方式有很多种,OSX系统的进程通讯方式更是多种多样,笔者暂时只写过xpc和有名管道通讯的框架,特此记录一下自己的心得。



首先基于Pipe有名管道的进程通讯,我们将管道创建,打开,读取,写入等 *** 作封装到CPipeWrapper的类中,方便对管道的一系列 *** 作。

class CPipeWrapper{public:    CPipeWrapper();    ~CPipeWrapper();    int CreatePipe(const char *szPipename,int mode = 0777);    int OpenPipe(const char *szPipename,int mode);    ssize_t ReadFromPipe(voID *pBuffer,size_t nLen);    ssize_t WritetoPipe(voID *pBuffer,size_t nLen);    int GetPipeDescr() const;private:    int m_pipe;};

在进程通讯过程中,我们需要处理各种定义的指令和包,在此我们需要对指令包进行简单地封装 *** 作。定义CCommandDataWrapper方便我们对指令的传输和处理 *** 作。

#pragma pack(1)template <class ParaM_DATA_TYPE>struct CommandData{    COMMAND_TYPE type;    uint32_t CRC;    uint32_t bufferLen;    ParaM_DATA_TYPE paramDataStruct;};template <class ParaM_DATA_TYPE>class CCommandDataWrapper{public:    bool initializeWithCommandData(const voID *pCommandData,size_t nDataLen);    bool initializeWithCommandStruct(ParaM_DATA_TYPE paramData,COMMAND_TYPE type);    const voID* getData() const;    uint32_t getDataLen() ;    ParaM_DATA_TYPE getParamData();    COMMAND_TYPE getType() ;    protected:    struct CommandData<ParaM_DATA_TYPE> m_data;};


在此,我们定义好COMMAND_TYPE和对应的ParaM_DATA_TYPE即可产生相对应的CCommandDataWrapper对象。


建立CConnectionWrapper来维护管理进程通讯,由于服务端和客户端的差异性,分别写cclIEntConnectionWrapper和CServerConnectionWrapper继承于CConnectionWrapper,方便对服务端客户端的消息处理。

#define MSG_ID_INVALID 0#define MSG_ID_START 0x10class CConnectionWrapper{public:    CConnectionWrapper(bool bIsServer);    ~CConnectionWrapper();    virtual bool InitializeGetMessage();    virtual bool InitializeSendMessage();    virtual voID SendCmd_async(CCommandDataWrapper<char> * lpBufferIn,int msgiD = MSG_ID_INVALID);    virtual voID HandleMessage(char *rsvBuff);    virtual bool IsContinue();    private:    static voID* GetMsgThread(voID *arg);    private:    bool m_bInitializeSendMsg;    bool m_bInitializeGetMsgloop;    bool m_bIsServer;    pthread_t m_getMsgThread;    protected:    CPipeWrapper m_pipe1,m_pipe2;    bool m_bContinue;};

对于CCommanDWrapper中的InitializeSendMessage()和InitializeGetMessage(),将管道收发消息这两个过程动态地分离了出来;由异步发送消息函数SendCmd_async的参数可以看出,我们对数据包的传输处理都是通过CCommadDataWrapper<char> *类型处理;在虚函数HandleMessage对管道返回的buffer进行处理 *** 作。当然此处获取消息只写了单一的线程m_getMsgThread;


对于客户端,当我们需要一个同步的发送命令的方法的时候,现在的设计当然是不够的,我们还需要一种类似于

SendCmd_sync(CCommandDataWrapper<char> *pCmdDataObjIn,

                                    voID *pCmdDataObjOut,

                                    unsignedint uiTimeout)

的方法,当然在现有基础上,我们将异步要改为同步的话,我们还需要引入Semaphore和Mutex,在Connection内部维护一个 “消息编号——数据” 对应的map对象,在同步消息函数执行过程中,等待消息对应的信号量,信号量变为有信号状态以后,调用拷贝将map中对应的数据拷贝出来,当然,在对map对象 *** 作的过程中,我们需要对其进行加锁。

voID cclIEntConnectionWrapper::SendCommand_sync(CCommandDataWrapper<char> *lpBufferIn,voID *lpBufferOut,unsigned int uiTimeout){    if (NulL == lpBufferIn || NulL == lpBufferOut || !InitializeSendMessage())    {        return;    }    MSG_MAPPing msgMapPing = { 0 };    CSemaphoreHelper semHelper;    char semname[32] = { 0 };    int msgiD = MSG_ID_INVALID;    CPipeDataWrapper pipeDataIn;    {        CLockerGuard lock(m_locker);        msgiD = m_msgiD;        sprintf(semname,"Jovi_sem_%d_",m_msgiD);        msgMapPing.signal = semHelper.CreateSemaphore(semname,0);        m_map_RsvMsg.insert(std::make_pair(m_msgiD ++,msgMapPing));        pipeDataIn.InitializeWithCmdDataWrapper(lpBufferIn,msgiD);    }    m_pipe1.WritetoPipe(pipeDataIn.getMessage(),PIPE_BUF);        //wait sem     memset(lpBufferOut,PIPE_BUF + 1);    unsigned int nWait = 0;    while (true)    {        if(semHelper.TryWaitSemaphore(msgMapPing.signal))        {            CLockerGuard lock(m_locker);            memcpy(lpBufferOut,m_map_RsvMsg[msgiD].bufferOut,PIPE_BUF);            m_map_RsvMsg.erase(msgiD);            semHelper.DestroySemaphore(msgMapPing.signal);            semHelper.ClearSemaphore(semname);            break;        }        else if(nWait < uiTimeout)        {            sleep(1);            nWait ++;        }        else        {            //未获取到消息            CLockerGuard lock(m_locker);            //add your code             m_map_RsvMsg.erase(msgiD);            semHelper.DestroySemaphore(msgMapPing.signal);            semHelper.ClearSemaphore(semname);            break;        }    }}

typedef struct __MSG_MAPPing__{    sem_t *signal;    char bufferOut[PIPE_BUF + 1];}MSG_MAPPing,*PMSG_MAPPing;

由上,对于PIPE通讯的指令包封装,进一步在CCommandDataWrapper的基础上引入CPipeDataWrapper进行二次封装以对应PIPE通讯方式,这样的好处就是,当我们需要更换其他通讯方式的时候,我们可保持对外的SendCmd_sync和SendCmd_async的接口不变,替换PIPE通讯和数据处理就可以。

class cclIEntConnectionWrapper:public CConnectionWrapper{public:    static cclIEntConnectionWrapper & GetInstance()    {        static cclIEntConnectionWrapper instance;        return instance;    }        virtual ~cclIEntConnectionWrapper();    virtual bool InitializeGetMessage();    virtual bool InitializeSendMessage();    virtual voID SendCommand_sync(CCommandDataWrapper<char> * lpBufferIn,unsigned int uiTimeout);    virtual voID OnCommand(CCommandDataWrapper<char> *pCmdDataObj);    protected:    cclIEntConnectionWrapper();    cclIEntConnectionWrapper(const cclIEntConnectionWrapper &);    cclIEntConnectionWrapper & operator = (const cclIEntConnectionWrapper &);    virtual voID HandleMessage(char *rsvBuff);    private:    std::map<int,MSG_MAPPing> m_map_RsvMsg;    CMutexLocker m_locker;    int m_msgiD;};

UML图

总结

以上是内存溢出为你收集整理的Cocoa开发——PIPE通讯框架全部内容,希望文章能够帮你解决Cocoa开发——PIPE通讯框架所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1050959.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-25
下一篇 2022-05-25

发表评论

登录后才能评论

评论列表(0条)

保存