授权网关 SDK 接入步骤(Windows)

适用场景

  1. 客户端程序需要使用授权网关,但不希望让客户手工配置转发地址和成员账号。
  2. 授权网关功能与客户端集成,透明接入,授权网关通讯跟随客户端程序开启和关闭。

接入要求

  1. 需要有项目源码,开发环境正常可重新编译发布。
  2. 具备一定的开发能力,可根据 API 文档和程序样例加入 SDK 启动代码

准备素材

  1. 准备项目源码和开发环境,测试可正常编译。
  2. 下载 SDK 文件(点此下载),将 gateway.dll 文件复制到项目中,确保与 exe 程序文件在相同目录,注意区分 32 位和 64 位版本。

注意事项

  1. SDK 加载流程为:
    (1)加载 dll
    (2)调用启动函数
    (3)调用更新函数,加载配置
    (4)正常运行过程直到需要关闭
    (5)调用停止函数
    (6)卸载 dll
    退出程序前一定要调用停止函数,否则可能造成进程死锁。
  2. Windows 平台下请使用 WINAPI 宏修饰函数,函数名称无 @ 后缀,与系统函数风格相同。

加载说明

函数说明(按 C 语言)
1. gateway_start
int gateway_start();
功能:启动网关
返回:成功返回 0
2. gateway_stop
int gateway_stop();
功能:停止网关
返回:总是返回 0
3. gateway_update
int gateway_update(const char* config);
功能:更新配置
参数:config 是一个标准 C 字符串,包含 JSON 格式配置。
返回:成功返回 0
4. gateway_status
int gateway_status(char* buffer, int size);
功能:获取状态
参数:buffer 需提供一个缓冲区用于接收内容,size 为缓冲区大小。收到的内容是一个 JSON 格式文本。
返回:成功返回实际内容长度,错误或缓冲不足返回 0。
样例程序
  1. 引入头文件并声明函数
    #include <windows.h>
    #include <stdio.h>
    #include <string.h>
    
    // 定义函数指针类型
    typedef int WINAPI (*GATEWAY_START)();
    typedef int WINAPI (*GATEWAY_STOP)();
    typedef int WINAPI (*GATEWAY_UPDATE)(const char*);
    typedef int WINAPI (*GATEWAY_STATUS)(char*, int);
    
    // 全局变量来保存 DLL 模块句柄和函数指针
    HINSTANCE      hDLL           = NULL;
    GATEWAY_START  gateway_start  = NULL;
    GATEWAY_STOP   gateway_stop   = NULL;
    GATEWAY_UPDATE gateway_update = NULL;
    GATEWAY_STATUS gateway_status = NULL;
    
  2. 加载
    // 加载 DLL 并获取函数地址
    bool loadDll()
    {
        // 加载DLL
        hDLL = LoadLibrary(TEXT("gateway.dll"));
        if (hDLL == NULL)
        {
            printf("无法加载动态库\n");
            return false;
        }
    
        // 获取函数地址
        gateway_start  = (GATEWAY_START)GetProcAddress(hDLL, "gateway_start");
        gateway_stop   = (GATEWAY_STOP)GetProcAddress(hDLL, "gateway_stop");
        gateway_update = (GATEWAY_UPDATE)GetProcAddress(hDLL, "gateway_update");
        gateway_status = (GATEWAY_STATUS)GetProcAddress(hDLL, "gateway_status");
    
        if (!gateway_start || !gateway_stop || !gateway_update || !gateway_status)
        {
            printf("无法获取函数地址\n");
            FreeLibrary(hDLL);
            return false;
        }
    
        return true;
    }
    
  3. 释放
    // 释放 DLL
    void unloadDll()
    {
        if (hDLL != NULL) {
            gateway_start  = NULL; 
            gateway_stop   = NULL;
            gateway_update = NULL;
            gateway_status = NULL;
            FreeLibrary(hDLL);
            hDLL = NULL;
        }
    }
    
  4. 使用 main 函数演示生命周期
    int main()
    {
        // 加载 DLL
        if (!loadDll())
            return 1;
    
        // 启动网关
        int ret = gateway_start();
        if (ret != 0)
        {
            printf("无法启动: %d\n", ret);
            unloadDll();
            return 1;
        }
    
        // 更新配置(注意是一个 JSON 的数组,可以放多个转发配置,id 为自定义序号)
        const char* config = "[\n"
                             "  {\n"
                             "    \"id\":     1,\n"
                             "    \"remote\": \"lyxtest.a1.luyouxia.net:12345\",\n"
                             "    \"listen\": \"127.0.0.1:8888\",\n"
                             "    \"name\":   \"成员账号名称\",\n"
                             "    \"pwd\":    \"成员密码的 MD5 值\"\n"  // 
                             "  }\n"
                             "]";
        ret = gateway_update(config);
        if (ret != 0)
        {
            printf("无法更新配置: %d\n", ret);
            gateway_stop();
            unloadDll();
            return 1;
        }
        printf("成功更新配置\n");
    
        // 模拟运行过程(持续显示状态,一段时间后关闭)
        for (int i = 0; i < 60; i++) 
        { 
            char buf[1024] = {0}; 
            if (gateway_status(buf, sizeof(buf)) > 0)
                printf("状态: \n%s\n", buf);
            Sleep(1000); // 等待1秒
        }
    
        // 停止网关
        gateway_stop();
        printf("已停止\n");
    
        // 释放 DLL
        unloadDll();
        return 0;
    }
    
关于配置格式

配置格式是一个 JSON 数组,元素为每一个转发项,如果直接填写到测试代码中,请注意转义,线上系统建议远程加载或本地配置文件读取。程序可以重复调用 gateway_update 动态更新。

[
  {
    "id": 1,
    "remote": "lyxtest.a1.luyouxia.net:12345",
    "listen": "127.0.0.1:12345",
    "name":   "成员账号名称",
    "pwd":    "成员密码 MD5 值"
  }, 
  {
    "id": 2,
    "remote": "lyxtest.a1.luyouxia.net:12346",
    "listen": "127.0.0.1:12346",
    "name":   "成员账号名称",
    "pwd":    "成员密码 MD5 值"
  }
]