进程通讯方式有很多种,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;};
建立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通讯框架所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)