Skip to content

IPC通信模块

Warning

The current page still doesn't have a translation for this language.

You can read it through google translate.

概述

IPC(Inter-Process Communication,进程间通信)是SOUI UI框架提供的用于不同进程之间进行数据交换和功能调用的核心模块。该模块基于Windows的消息机制和共享内存技术实现,支持跨进程的函数调用、参数传递等功能。

IPC模块的主要特点: - 基于共享内存的数据传输 - 支持同步函数调用 - 支持复杂数据类型的序列化传输 - 提供客户端和服务端两种角色的支持 - 自动管理连接状态和资源释放

核心概念

主要组件

  1. IIpcHandle: IPC句柄接口,代表一个IPC连接的本地端点
  2. IIpcServer: IPC服务端接口,负责监听和管理多个客户端连接
  3. IIpcConnection: IPC连接接口,定义了连接的行为和参数
  4. IShareBuffer: 共享内存缓冲区接口,用于进程间数据传输
  5. IFunParams: 函数参数接口,定义了可序列化的函数参数

工作原理

IPC模块采用客户端-服务端架构:

  1. 服务端创建并监听特定窗口句柄
  2. 客户端通过窗口句柄连接到服务端
  3. 连接建立后,双方创建共享内存用于数据传输
  4. 客户端通过[CallFun]方法发起远程过程调用
  5. 服务端接收消息并处理相应的函数调用
  6. 处理结果通过共享内存返回给客户端

快速开始

定义通信协议

首先需要定义客户端和服务端之间的接口及参数结构:

// protocol.h

// 定义函数ID
enum {
    CID_AddInt = SOUI::FUN_ID_START,
    CID_AddString,

    SID_Hello,
};

// 定义参数结构体
struct Param_AddInt : FunParams_Base
{
    int a, b;
    int ret;
    FUNID(CID_AddInt)
    PARAMS2(Input, a,b)
    PARAMS1(Output,ret)
};

struct Param_Hello : FunParams_Base
{
    tstring text;
    FUNID(SID_Hello)
    PARAMS1(Input, text)
};

创建服务端

class CServerDlg : public SHostWnd, IIpcSvrCallback 
{
    SOUI::SAutoRefPtr<SOUI::IIpcServer> m_ipcSvr;

public:
    CServerDlg() {
        SOUI::SAutoRefPtr<IIpcFactory> ipcFac;
        m_comMgr.CreateIpcObject((IObjRef **)&ipcFac);
        ipcFac->CreateIpcServer(&m_ipcSvr);
    }

    void OnInit(IEvtArgs *e) {
        // 初始化服务端,使用当前窗口句柄作为标识
        m_ipcSvr->Init((ULONG_PTR)m_hWnd, this);
    }

    // 实现IIpcSvrCallback接口
    ULONG_PTR OnNewConnection(IIpcHandle *pIpcHandle, IIpcConnection **ppConn) override {
        CSvrConnect *pConn = new CSvrConnect(pIpcHandle);
        *ppConn = pConn;
        return ULONG_PTR(m_hWnd);
    }

    // 其他必须实现的方法...
};

创建连接对象

服务端需要为每个客户端连接创建对应的连接对象:

class CSvrConnect : public IServer, public SOUI::TObjRefImpl<SOUI::IIpcConnection> 
{
    SOUI::SAutoRefPtr<SOUI::IIpcHandle> m_ipcHandle;

public:
    CSvrConnect(SOUI::IIpcHandle *pHandle) : m_ipcHandle(pHandle) {}

    virtual int GetBufSize() const { return 1024 * 2; }
    virtual int GetStackSize() const { return 20; }

    virtual SOUI::IIpcHandle *GetIpcHandle() override {
        return m_ipcHandle;
    }

    virtual void BuildShareBufferName(ULONG_PTR idLocal, ULONG_PTR idRemote, TCHAR szBuf[MAX_PATH]) const override {
        _stprintf(szBuf, _T("share_buffer_%08x_2_%08x"), (DWORD)idLocal, (DWORD)idRemote);
    }

    // 处理客户端请求
    void OnAddInt(Param_AddInt &param) {
        param.ret = param.a + param.b;
    }

    FUN_BEGIN
    FUN_HANDLER(Param_AddInt, OnAddInt)
    FUN_END
};

创建客户端

class CClientConnect {
    SOUI::SAutoRefPtr<SOUI::IIpcHandle> m_ipcHandle;
    SComMgr2 m_comMgr;

public:
    CClientConnect() {
        SOUI::SAutoRefPtr<IIpcFactory> ipcFac;
        m_comMgr.CreateIpcObject((IObjRef **)&ipcFac);
        ipcFac->CreateIpcHandle(&m_ipcHandle);
        m_ipcHandle->SetIpcConnection(this);
    }

    // 连接到服务端
    bool Connect(HWND hSvr) {
        HRESULT hr = m_ipcHandle->ConnectTo((ULONG_PTR)m_hWnd, (ULONG_PTR)hSvr);
        return SUCCEEDED(hr);
    }

    // 调用远程函数
    int Add(int a, int b) {
        Param_AddInt params;
        params.a = a;
        params.b = b;
        m_ipcHandle->CallFun(&params);
        return params.ret;
    }

    virtual void BuildShareBufferName(ULONG_PTR idLocal, ULONG_PTR idRemote, TCHAR szBuf[MAX_PATH]) const {
        _stprintf(szBuf, _T("share_buffer_%08x_2_%08x"), (DWORD)idLocal, (DWORD)idRemote);
    }
};

高级特性

参数序列化

IPC模块支持自动序列化复杂数据类型。通过特化[SParamStream]模板可以支持自定义类型的序列化:

template<>
inline SParamStream & SParamStream::operator<<(const tstring & str)
{
    int nSize = (int)str.size();
    GetBuffer()->Write(&nSize, sizeof(int));
    GetBuffer()->Write(str.c_str(), nSize*sizeof(TCHAR));
    return *this;
}

template<>
inline SParamStream & SParamStream::operator >> (tstring & str)
{
    int nSize = 0;
    GetBuffer()->Read(&nSize, sizeof(int));
    TCHAR *pBuf = new TCHAR[nSize];
    GetBuffer()->Read(pBuf, nSize*sizeof(TCHAR));
    str = tstring(pBuf, nSize);
    delete[]pBuf;
    return *this;
}

递归调用

IPC模块支持在处理函数调用时发起新的IPC调用,实现递归功能:

void CClientConnect::OnSum(Param_Sum &param)
{
    // 递归调用计算 1+2+...+n
    SASSERT(param.n >= 1);
    if (param.n == 1)
    {
        param.nRet = 1;
    }
    else
    {
        Param_Sum p2;
        p2.n = param.n - 1;
        m_ipcHandle->CallFun(&p2);
        param.nRet = param.n + p2.nRet;
    }
}

最佳实践

错误处理

确保始终检查[CallFun]的返回值以确定调用是否成功:

Param_AddInt params;
params.a = 1;
params.b = 2;
if (m_ipcHandle->CallFun(&params)) {
    // 成功获取结果
    int result = params.ret;
} else {
    // 处理调用失败的情况
}

资源管理

确保正确断开连接并释放资源:

// 断开连接
m_ipcHandle->Disconnect();

// 清理资源由智能指针自动完成

性能优化

  1. 合理设置共享内存大小([GetBufSize])和栈深度([GetStackSize])
  2. 避免传递过大的数据结构
  3. 尽量减少不必要的IPC调用

API参考

IIpcHandle主要方法

  • ConnectTo: 连接到指定的服务端
  • Disconnect: 断开连接
  • CallFun: 调用远程函数
  • IsConnected: 检查连接状态
  • GetSendBuffer/GetRecvBuffer: 获取发送/接收缓冲区

IIpcServer主要方法

  • Init: 初始化服务端
  • CheckConnectivity: 检查客户端连接状态
  • EnumClient: 枚举所有客户端连接
  • Disconnect: 断开指定客户端连接

IIpcConnection主要方法

  • GetBufSize: 获取共享内存缓冲区大小
  • GetStackSize: 获取调用栈深度
  • GetIpcHandle: 获取关联的IPC句柄
  • BuildShareBufferName: 构建共享内存名称

示例项目

请参考soui4/demos/ipcdemo目录中的完整示例,其中包含了完整的客户端和服务端实现。