# C/C++ 快速接入

泡椒云网络验证官方提供的 C/C++ SDK,同时提供 C(C99)与 C++(C++17)两种实现, 唯一外部依赖 libcurl(+线程库),支持 Linux / macOS / Windows。

# 接入须知

# 获取方式

  • 下载地址:请登录开发者后台,在首页「最新SDK」处下载
  • 压缩包内容:
    • c/:C 版(pjysdk.h 单头库 + demo.c 示例)
    • cpp/:C++ 版(pjysdk.hpppjysdk.cpp、内置 nlohmann/json.hpp + demo.cpp 示例)
    • CMakeLists.txt:CMake 示例工程,一次构建两个 demo

# 依赖安装(libcurl)

  • macOS:系统自带
  • Debian/Ubuntu:sudo apt-get install libcurl4-openssl-dev
  • CentOS/RHEL:sudo yum install libcurl-devel
  • Windows(任选其一):
    • vcpkg(MSVC)vcpkg install curl
    • MSYS2 / MinGW-w64pacman -S mingw-w64-x86_64-curl

线程库:Linux / macOS / MinGW 链接 -lpthread;MSVC 下 C 版自动切换为 原生 Win32 线程、C++ 版使用 std::thread,两版均可用 MSVC 直接编译。

# C 版接入

pjysdk.h 是单头库:在一个 .c 文件里定义宏再包含,即引入实现; 其余文件只 #include "pjysdk.h"

#define PJYSDK_IMPLEMENTATION
#include "pjysdk.h"
1
2

编译:

cc your_app.c -lcurl -lpthread -o your_app
1

# C++ 版接入

cpp/ 目录拷进你的项目(如 third_party/pjysdk/),pjysdk.cpp 加入构建, 代码里 #include "pjysdk.hpp"

c++ -std=c++17 your_app.cpp third_party/pjysdk/pjysdk.cpp \
    -I third_party/pjysdk \
    -lcurl -lpthread \
    -o your_app
1
2
3
4

CMake 集成:

find_package(CURL REQUIRED)
find_package(Threads REQUIRED)

add_executable(your_app main.cpp third_party/pjysdk/pjysdk.cpp)
target_include_directories(your_app PRIVATE third_party/pjysdk)
target_link_libraries(your_app PRIVATE CURL::libcurl Threads::Threads)
1
2
3
4
5
6

# 调用形式与返回值

C++ 版(命名空间 pjy):

  • 每个 API 返回 Resp<T>{code, message, result}code == 0 表示成功;
  • 网络重试耗尽或服务端签名校验失败时抛出 pjy::PjyException,请用 try/catch 包裹;
  • 所有公开方法可并发调用。

C 版(前缀 pjy_):

  • 每个 API 返回 pjy_resp,先看 ok 字段:ok == 0 表示网络耗尽或签名校验失败 (错误描述在 error);ok == 1 后再看业务码 code(0 为成功);
  • result 为解析后的 JSON 节点,用 pjy_json_str / pjy_json_i64 / pjy_json_obj 读取;
  • 每个返回的 pjy_resp 用完必须调用 pjy_resp_free 释放
  • 所有公开函数可并发调用。

# 使用示例(C++)

#include <iostream>
#include "pjysdk.hpp"

int main() {
    // 初始化 SDK,appKey 和 appSecret 在泡椒云开发者后台获取
    pjy::PJYSDK sdk("AppKey", "AppSecret");
    sdk.setDebug(true);

    // 心跳失败回调(默认回调会打印错误并退出进程,生产环境请自行设置)
    sdk.onHeartbeatFail([&sdk](const pjy::Resp<pjy::HeartbeatResult>& r) {
        std::cout << "心跳失败: " << r.code << " " << r.message << std::endl;
        if (r.code == 10214) {
            std::exit(1);  // 登录状态已失效(被挤下线等)
        }
    });

    sdk.setDeviceID("你的设备唯一ID");  // 需自行生成,保证一机一码
    sdk.setCard("卡密");

    try {
        // 卡密登录,成功后自动开始心跳保活
        auto ret = sdk.cardLogin();
        if (ret.code != 0) {
            std::cout << "登录失败: " << ret.message << std::endl;
            return 1;
        }
        std::cout << "登录成功,卡密类型: " << ret.result.cardType << std::endl;
        std::cout << "剩余时间(秒): " << sdk.getTimeRemaining() << std::endl;
    } catch (const pjy::PjyException& e) {
        std::cout << "请求异常: " << e.what() << std::endl;
        return 1;
    }
    // 你的业务逻辑……
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

# 使用示例(C)

#include <stdio.h>
#include <stdlib.h>

#define PJYSDK_IMPLEMENTATION
#include "pjysdk.h"

static void on_hb_fail(const pjy_resp *r, void *user) {
    (void)user;
    printf("心跳失败: %d %s\n", r->code, r->message ? r->message : "");
    if (r->code == 10214) {
        exit(1);  /* 登录状态已失效(被挤下线等) */
    }
}

int main(void) {
    /* 初始化 SDK,appKey 和 appSecret 在泡椒云开发者后台获取 */
    pjy_sdk *s = pjy_new("AppKey", "AppSecret");
    pjy_set_debug(s, 1);
    pjy_on_heartbeat_fail(s, on_hb_fail, NULL);

    pjy_set_device_id(s, "你的设备唯一ID"); /* 需自行生成,保证一机一码 */
    pjy_set_card(s, "卡密");

    /* 卡密登录,成功后自动开始心跳保活 */
    pjy_resp r = pjy_card_login(s);
    if (!r.ok) {
        printf("请求异常: %s\n", r.error ? r.error : "");
        pjy_resp_free(&r);
        pjy_free(s);
        return 1;
    }
    if (r.code != 0) {
        printf("登录失败: %s\n", r.message ? r.message : "");
        pjy_resp_free(&r);
        pjy_free(s);
        return 1;
    }
    printf("登录成功,卡密类型: %s\n", pjy_json_str(r.result, "card_type"));
    printf("剩余时间(秒): %d\n", pjy_get_time_remaining(s));
    pjy_resp_free(&r);

    /* 你的业务逻辑…… */

    pjy_free(s); /* 退出时释放(内部会停止心跳线程) */
    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

# 可更改配置

void setDebug(bool debug);          // C: pjy_set_debug(s, debug)
void setAutoHeartbeat(bool enable); // C: pjy_set_auto_heartbeat(s, enable)
1
2
  • setDebug : 默认为 true,开启后会在控制台输出每次请求的详细信息
  • setAutoHeartbeat : 是否自动开启心跳,默认 true,不建议修改

# 初始化

# 创建 SDK

pjy::PJYSDK sdk(appKey, appSecret);            // C++(不可拷贝,可长期持有)
pjy_sdk *s = pjy_new(app_key, app_secret);     // C,退出时 pjy_free(s)
1
2
参数 必传 类型 说明
appKey string 软件的 app_key,开发者后台获取
appSecret string 软件的 app_secret,开发者后台获取

# 设置设备唯一 ID

void setDeviceID(const std::string& deviceID);        // C++
void pjy_set_device_id(pjy_sdk *s, const char *id);   // C
1
2
参数 必传 类型 说明
deviceID string 用户设备唯一标识(长度不超过45位)

# 设置卡密

void setCard(const std::string& card);            // C++
void pjy_set_card(pjy_sdk *s, const char *card);  // C
1
2
参数 必传 类型 说明
card string 用户填写的卡密(长度不超过45位)

# 设置用户账号

void setUser(const std::string& username, const std::string& password);       // C++
void pjy_set_user(pjy_sdk *s, const char *username, const char *password);    // C
1
2
参数 必传 类型 说明
username string 用户名(长度不超过20位)
password string 用户密码(长度 6-30 位)

# 心跳

登录成功后 SDK 自动启动心跳线程,无需手动管理。

# 心跳失败回调

void onHeartbeatFail(HeartbeatFailFn fn);                                     // C++
void pjy_on_heartbeat_fail(pjy_sdk *s, pjy_heartbeat_fail_fn fn, void *user); // C,user 为自定义指针
1
2

心跳返回 code != 0 时触发。默认回调会打印错误并退出进程,生产环境请自行设置。 常见的 code == 10214 表示登录状态已失效(超时未发心跳、被挤下线、后台冻结等), 应引导用户重新登录。

# 获取心跳结果

Resp<HeartbeatResult> getHeartbeatResult();     // C++
pjy_resp pjy_get_heartbeat_result(pjy_sdk *s);  // C,用完需 pjy_resp_free
1
2

code == 0 表示心跳正常,否则 message 包含错误信息。

# 获取剩余时长

int getTimeRemaining();                    // C++
int pjy_get_time_remaining(pjy_sdk *s);    // C
1
2

返回剩余有效秒数,不发起网络请求。

# 卡密登录

调用前需先设置卡密与设备 ID。登录成功后自动启动心跳。

Resp<CardLoginResult> cardLogin();   // C++
pjy_resp pjy_card_login(pjy_sdk *s); // C
1
2

返回值:成功时 result 包含 card_type(卡密类型)、expires(过期时间)、 expires_ts(过期时间戳秒)、config(自定义配置)等字段。 C++ 直接读 ret.result.cardType 等;C 用 pjy_json_str(r.result, "card_type")pjy_json_i64(r.result, "expires_ts") 读取。

# 卡密退出登录

Resp<Empty> cardLogout();             // C++
pjy_resp pjy_card_logout(pjy_sdk *s); // C
1
2

退出登录会停止心跳。

# 卡密解绑设备

需在开发者后台配置软件允许解绑,且需在卡密登录后调用。

Resp<Empty> cardUnbindDevice();              // C++
pjy_resp pjy_card_unbind_device(pjy_sdk *s); // C
1
2

# 卡密设置解绑密码

需在开发者后台配置软件允许解绑。该密码用于设备丢失等情况解绑。需在卡密登录后调用。

Resp<Empty> setCardUnbindPassword(const std::string& password);          // C++
pjy_resp pjy_set_card_unbind_password(pjy_sdk *s, const char *password); // C
1
2
参数 必传 类型 说明
password string 解绑密码,6-10位

# 卡密通过密码解绑设备

无需登录,调用前需先设置卡密。

Resp<Empty> cardUnbindDeviceByPassword(const std::string& password);            // C++
pjy_resp pjy_card_unbind_device_by_password(pjy_sdk *s, const char *password);  // C
1
2
参数 必传 类型 说明
password string 解绑密码,6-10位

# 卡密充值(以卡充卡)

Resp<Empty> cardRecharge(const std::string& card, const std::string& useCard);     // C++
pjy_resp pjy_card_recharge(pjy_sdk *s, const char *card, const char *use_card);    // C
1
2
参数 必传 类型 说明
card string 被充值的卡密
useCard string 用于充值的卡密

# 用户注册(通过卡密)

调用前需先设置设备 ID。

Resp<Empty> userRegister(const std::string& username,
                         const std::string& password,
                         const std::string& card);      // C++
pjy_resp pjy_user_register(pjy_sdk *s, const char *username,
                           const char *password, const char *card); // C
1
2
3
4
5
参数 必传 类型 说明
username string 用户名(不超过20位)
password string 密码(6-30位)
card string 注册使用的卡密

# 用户登录

调用前需先设置用户账号与设备 ID。登录成功自动心跳。

Resp<UserLoginResult> userLogin();   // C++
pjy_resp pjy_user_login(pjy_sdk *s); // C
1
2

# 用户退出登录

Resp<Empty> userLogout();             // C++
pjy_resp pjy_user_logout(pjy_sdk *s); // C
1
2

# 用户修改密码

Resp<Empty> userChangePassword(const std::string& username,
                               const std::string& password,
                               const std::string& newPassword);  // C++
pjy_resp pjy_user_change_password(pjy_sdk *s, const char *username,
                                  const char *password, const char *new_password); // C
1
2
3
4
5
参数 必传 类型 说明
username string 用户名
password string 当前密码
newPassword string 新密码(6-30位)

# 用户充值(通过卡密)

Resp<Empty> userRecharge(const std::string& username, const std::string& card); // C++
pjy_resp pjy_user_recharge(pjy_sdk *s, const char *username, const char *card); // C
1
2
参数 必传 类型 说明
username string 用户名
card string 充值卡密

# 用户解绑设备

需在用户登录后调用。

Resp<Empty> userUnbindDevice();              // C++
pjy_resp pjy_user_unbind_device(pjy_sdk *s); // C
1
2

# 试用登录

调用前需先设置设备 ID。登录成功自动心跳。

Resp<TrialLoginResult> trialLogin();  // C++
pjy_resp pjy_trial_login(pjy_sdk *s); // C
1
2

# 试用退出登录

Resp<Empty> trialLogout();             // C++
pjy_resp pjy_trial_logout(pjy_sdk *s); // C
1
2

仅清除本地状态并停止心跳,无网络请求。

# 获取卡密配置

Resp<CardConfigResult> getCardConfig();    // C++,成功时 result.config 为配置内容
pjy_resp pjy_get_card_config(pjy_sdk *s);  // C,pjy_json_str(r.result, "config")
1
2

# 更改卡密配置

Resp<Empty> updateCardConfig(const std::string& config);         // C++
pjy_resp pjy_update_card_config(pjy_sdk *s, const char *config); // C
1
2
参数 必传 类型 说明
config string 自定义配置(不超过512位)

# 获取用户配置

Resp<UserConfigResult> getUserConfig();    // C++
pjy_resp pjy_get_user_config(pjy_sdk *s);  // C
1
2

# 更改用户配置

Resp<Empty> updateUserConfig(const std::string& config);         // C++
pjy_resp pjy_update_user_config(pjy_sdk *s, const char *config); // C
1
2
参数 必传 类型 说明
config string 自定义配置(不超过512位)

# 获取软件配置

Resp<SoftwareConfigResult> getSoftwareConfig(); // C++
pjy_resp pjy_get_software_config(pjy_sdk *s);   // C
1
2

# 获取软件公告

Resp<SoftwareNoticeResult> getSoftwareNotice(); // C++,result.notice 为公告内容
pjy_resp pjy_get_software_notice(pjy_sdk *s);   // C,pjy_json_str(r.result, "notice")
1
2

# 获取软件最新版本

Resp<SoftwareVersionResult> getSoftwareLatestVersion(const std::string& currentVer); // C++
pjy_resp pjy_get_software_latest_version(pjy_sdk *s, const char *current_ver);       // C
1
2
参数 必传 类型 说明
currentVer string 当前本地版本(不超过30位)

成功时 result 包含 versiondownload_urlupdate_log

# 获取远程变量

Resp<RemoteVarResult> getRemoteVar(const std::string& key);  // C++
pjy_resp pjy_get_remote_var(pjy_sdk *s, const char *key);    // C
1
2
参数 必传 类型 说明
key string 远程变量名(不超过64位)

# 获取远程数据

Resp<RemoteDataResult> getRemoteData(const std::string& key); // C++
pjy_resp pjy_get_remote_data(pjy_sdk *s, const char *key);    // C
1
2
参数 必传 类型 说明
key string 数据 key(不超过64位)

# 操作远程数据

# 新增远程数据

Resp<Empty> createRemoteData(const std::string& key, const std::string& value);   // C++
pjy_resp pjy_create_remote_data(pjy_sdk *s, const char *key, const char *value);  // C
1
2
参数 必传 类型 说明
key string 数据 key(不超过64位)
value string 数据值(不超过256位)

# 修改远程数据

Resp<Empty> updateRemoteData(const std::string& key, const std::string& value);   // C++
pjy_resp pjy_update_remote_data(pjy_sdk *s, const char *key, const char *value);  // C
1
2
参数 必传 类型 说明
key string 数据 key(不超过64位)
value string 数据值(不超过256位)

# 删除远程数据

Resp<Empty> deleteRemoteData(const std::string& key);         // C++
pjy_resp pjy_delete_remote_data(pjy_sdk *s, const char *key); // C
1
2
参数 必传 类型 说明
key string 数据 key(不超过64位)

# 调用远程函数

// C++:params 为 JSON 数组,返回值在 result.ret(任意 JSON)
Resp<RemoteFuncResult> callRemoteFunc(const std::string& funcName,
                                      const nlohmann::json& params = nlohmann::json::array());
// C:params_json 为已序列化的 JSON 数组文本(NULL 视为 "[]"),返回值在 result 的 "return" 节点
pjy_resp pjy_call_remote_func(pjy_sdk *s, const char *func_name, const char *params_json);
1
2
3
4
5
参数 必传 类型 说明
funcName string 远程函数名(不超过64位)
params JSON数组 参数列表,如 [1, 2]

示例 远程函数定义(JavaScript):

function add(a, b) {
  return a + b;
}
1
2
3

C++ 调用:

auto ret = sdk.callRemoteFunc("add", nlohmann::json::array({1, 2}));
if (ret.code == 0) {
    std::cout << "计算结果: " << ret.result.ret << std::endl;
}
1
2
3
4

C 调用:

pjy_resp r = pjy_call_remote_func(s, "add", "[1, 2]");
if (r.ok && r.code == 0) {
    printf("计算结果: %lld\n", (long long)pjy_json_i64(r.result, "return"));
}
pjy_resp_free(&r);
1
2
3
4
5

# 释放资源

// C++:PJYSDK 析构时自动停止心跳线程(对象离开作用域即可)
// C:退出时必须调用,内部会停止心跳线程并释放全部内存
void pjy_free(pjy_sdk *s);
1
2
3

提示:

  • C++ 版业务状态通过 Resp<T>.code 判断(0 成功),网络/签名异常抛 PjyException
  • C 版先看 pjy_resp.ok(0 表示网络/签名异常,见 error),再看 code(0 成功), 且每个 pjy_resp 用完必须 pjy_resp_free。 返回码含义见接入须知中的对照表。