日日摸夜夜添夜夜爽出水_dvd碟片色爱_麻豆wwwcom内射软件_国产欧美色一区二区三区_中字幕视频在线永久在线观看免费_99久久在线视频精品店_国产精品1区2区3区在线观看 _两性午夜色视频免费网站_国产精品女同久久久久电影院_国产一区二区不卡亚洲涩情

簡體中文

基于P2PTunnelAPIs和TCPIP協(xié)議開發(fā)NAS(或者攝像頭)-APP端

P2PTunnelAPIs APP端(Agent)開發(fā)指南 | TUTK P2P SDK 開發(fā)手冊

一、API調(diào)用流程圖

基于P2PTunnelAPIs和TCPIP協(xié)議開發(fā)NAS-app-2.png

圖 1:APP端 Agent 初始化、連線、映射、釋放完整流程

二、核心開發(fā)步驟(APP端 Agent)

以下為 P2PTunnel Agent(APP端)的核心開發(fā)流程,包含初始化、P2P連線、端口映射、資源釋放等關(guān)鍵步驟,適配 SDK 全版本,支持多設(shè)備連接場景。

(一)Agent 初始化(必選)
1. 設(shè)置 SDK 許可證密鑰

啟動 Agent 前需先通過 TUTK 提供的許可證密鑰激活 SDK,否則后續(xù)接口調(diào)用會失敗。

// 設(shè)置SDK許可證密鑰(由 TUTK 官方提供) int ret = TUTK_SDK_Set_License_Key(sdk_license_key); if (ret != TUTK_ER_NoERROR) {    printf("TUTK_SDK_Set_License_Key() error[%d]\n", ret);    return -1; }
說明:sdk_license_key 需妥善保管,避免泄露;APP 啟動時僅需調(diào)用一次。
2. 初始化 P2PTunnel Agent 模塊

根據(jù) SDK 版本選擇對應(yīng)的初始化接口,新版本支持局域網(wǎng)直連模式(提升傳輸速度,需設(shè)備端配合開啟)。

// 定義最大支持的設(shè)備連接數(shù)(自定義,如8臺設(shè)備) #define MAX_SERVER_CONNECT_NUM 8 // 初始化P2PTunnel模塊(根據(jù)SDK版本選擇接口) #if _USE_SDK_VERSION_BELOW_4_3_5_0_ // 舊版本初始化接口(SDK版本 < 4.3.5.0) // 參數(shù):最大支持的設(shè)備連接數(shù) ret = P2PTunnelAgentInitialize(MAX_SERVER_CONNECT_NUM); if (ret != TUTK_ER_NoERROR) {    printf("P2PTunnelAgentInitialize() error[%d]\n", ret);    return -1; } #else // 新版本初始化接口(SDK版本 >= 4.3.5.0) // 參數(shù)1:最大支持的設(shè)備連接數(shù) // 參數(shù)2:1=開啟局域網(wǎng)直連(提升速度,局域網(wǎng)內(nèi)數(shù)據(jù)不加密);0=關(guān)閉 // 注意:設(shè)備端需同樣設(shè)置為1才能啟用直連模式,否則不生效 ret = P2PTunnelAgentInitialize2(MAX_SERVER_CONNECT_NUM, 1); if (ret != TUTK_ER_NoERROR) {    printf("P2PTunnelAgentInitialize2() error[%d]\n", ret);    return -1; } #endif
說明:初始化接口僅需在 APP 啟動時調(diào)用一次,多次調(diào)用可能導(dǎo)致資源沖突。
3. 注冊隧道狀態(tài)回調(diào)函數(shù)

注冊回調(diào)函數(shù)以監(jiān)聽 P2P 會話狀態(tài)變更(如連接建立、斷開、異常),便于 APP 同步UI狀態(tài)。

// 注冊P2P隧道狀態(tài)回調(diào)函數(shù) // 參數(shù)1:回調(diào)函數(shù)指針(需自定義實(shí)現(xiàn),如TunnelStatusCB) // 參數(shù)2:自定義參數(shù)(傳遞給回調(diào)函數(shù),如APP上下文信息) P2PTunnelAgent_GetStatus(TunnelStatusCB, (void*)args);
說明:TunnelStatusCB 需按 SDK 定義的函數(shù)原型實(shí)現(xiàn),示例:void TunnelStatusCB(int SID, int status, void* pArg),其中 SID 為會話ID,status 為狀態(tài)碼。
(二)建立 P2P 隧道連接(必選)
1. 調(diào)用擴(kuò)展連接接口

通過設(shè)備 UID 發(fā)起 P2P 連接,支持新版本 DTLS 加密協(xié)議,同時兼容舊版本設(shè)備(自動降級為舊接口)。

// 設(shè)備信息結(jié)構(gòu)體(存儲設(shè)備UID、認(rèn)證信息等,自定義) typedef struct {    char uid[64];          // 設(shè)備唯一標(biāo)識(由設(shè)備端提供)    char username[32];     // 設(shè)備認(rèn)證用戶名    char password[64];     // 設(shè)備認(rèn)證密碼    // 其他擴(kuò)展字段... } sTunnelInfo; // 初始化設(shè)備信息(示例:從APP配置或用戶輸入獲?。? sTunnelInfo tunnelInfo = {    .uid = "DEVICE_UID_123456", // 目標(biāo)設(shè)備UID    .username = "tutk_agent",   // 預(yù)設(shè)用戶名    .password = "agent_pass123" // 預(yù)設(shè)密碼 }; // 嘗試通過新版本擴(kuò)展接口建立P2P隧道連接 int SID = P2PTunnelAgent_Connect_Ex(    tunnelInfo.uid,                  // 目標(biāo)設(shè)備UID    TunnelClientAuthentication,      // 客戶端認(rèn)證回調(diào)函數(shù)(填充賬號密碼)    (void*)&tunnelInfo               // 自定義參數(shù)(傳遞設(shè)備信息給回調(diào)) ); // 處理"遠(yuǎn)程不支持DTLS"錯誤(舊版本設(shè)備兼容邏輯) if (SID == TUNNEL_ER_REMOTE_NOT_SUPPORT_DTLS) {    printf("遠(yuǎn)程設(shè)備為舊版本SDK,不支持DTLS,切換至舊版本連接接口\n");    // 初始化舊版本認(rèn)證數(shù)據(jù)結(jié)構(gòu)(按舊協(xié)議要求)    sAuthData authData = {0};        // 自動初始化緩沖區(qū)為0    int nDeviceErr = 0;              // 接收設(shè)備端返回的錯誤碼    // 填充舊版本默認(rèn)認(rèn)證信息(需與設(shè)備端舊版本認(rèn)證邏輯匹配)    strncpy(authData.szUsername, "Tutk.com", sizeof(authData.szUsername) - 1);    strncpy(authData.szPassword, "P2P Platform", sizeof(authData.szPassword) - 1);    // 調(diào)用舊版本連接接口重試    SID = P2PTunnelAgent_Connect(        tunnelInfo.uid,              // 目標(biāo)設(shè)備UID        (void*)&authData,            // 舊版本認(rèn)證數(shù)據(jù)        sizeof(sAuthData),           // 認(rèn)證數(shù)據(jù)長度        &nDeviceErr                  // 輸出設(shè)備端錯誤碼(便于排查)    );    // 打印舊版本連接結(jié)果    printf("舊版本接口連接結(jié)果 - UID: %s, 會話ID(SID): %d, 設(shè)備錯誤碼: %d\n",           tunnelInfo.uid, SID, nDeviceErr); } // 處理最終連接結(jié)果 if (SID < 0) {    printf("P2P連接失敗,錯誤碼: %d(參考SDK文檔錯誤碼說明)\n", SID);    return -1; } else {    printf("P2P連接成功,會話ID(SID): %d(后續(xù)操作需使用該SID)\n", SID); }
說明:連接成功后返回的 SID 為會話唯一標(biāo)識,后續(xù)端口映射、斷開連接等操作需傳入該 SID。
2. 實(shí)現(xiàn)客戶端認(rèn)證回調(diào)函數(shù)

回調(diào)函數(shù)用于向 SDK 填充設(shè)備認(rèn)證的用戶名和密碼,支持按設(shè)備區(qū)分不同認(rèn)證信息(核心?。?。

/** * P2P隧道客戶端認(rèn)證回調(diào)函數(shù) * @brief 向SDK填充設(shè)備認(rèn)證的用戶名和密碼,支持多設(shè)備差異化認(rèn)證 * @param cszAccount 輸出參數(shù):用戶名緩沖區(qū)(SDK讀取該緩沖區(qū)進(jìn)行認(rèn)證) * @param nAccountMaxLength cszAccount緩沖區(qū)最大長度(含字符串終止符'\0') * @param cszPassword 輸出參數(shù):密碼緩沖區(qū)(SDK讀取該緩沖區(qū)進(jìn)行認(rèn)證) * @param nPasswordMaxLength cszPassword緩沖區(qū)最大長度(含字符串終止符'\0') * @param pArg 自定義參數(shù):傳遞的sTunnelInfo結(jié)構(gòu)體指針(區(qū)分不同設(shè)備) */ // 全局默認(rèn)認(rèn)證信息(適用于無自定義信息的設(shè)備) #define DEFAULT_TUNNEL_USERNAME "default_user" #define DEFAULT_TUNNEL_PASSWORD "default_pass" void TunnelClientAuthentication(    char *cszAccount,    uint32_t nAccountMaxLength,    char *cszPassword,    uint32_t nPasswordMaxLength,    const void *pArg ) {    // 將自定義參數(shù)轉(zhuǎn)換為設(shè)備信息結(jié)構(gòu)體(區(qū)分不同設(shè)備)    sTunnelInfo *deviceInfo = (sTunnelInfo *)pArg;    // 校驗(yàn)參數(shù)有效性    if (cszAccount == NULL || cszPassword == NULL || nAccountMaxLength == 0 || nPasswordMaxLength == 0) {        printf("[%s] 無效參數(shù):緩沖區(qū)為空或長度為0\n", __func__);        return;    }    // 按設(shè)備填充認(rèn)證信息(核心差異化邏輯)    if (deviceInfo != NULL && strlen(deviceInfo->uid) > 0) {        // 有自定義設(shè)備信息:使用設(shè)備專屬的用戶名密碼        printf("[%s] 設(shè)備認(rèn)證 - UID: %s, 用戶名: %s\n",               __func__, deviceInfo->uid, deviceInfo->username);                // 安全填充用戶名(避免緩沖區(qū)溢出)        strncpy(cszAccount, deviceInfo->username, nAccountMaxLength - 1);        cszAccount[nAccountMaxLength - 1] = '\0';        // 安全填充密碼(避免緩沖區(qū)溢出)        strncpy(cszPassword, deviceInfo->password, nPasswordMaxLength - 1);        cszPassword[nPasswordMaxLength - 1] = '\0';    } else {        // 無自定義設(shè)備信息:使用全局默認(rèn)認(rèn)證信息        printf("[%s] 無設(shè)備自定義信息,使用默認(rèn)認(rèn)證\n", __func__);        strncpy(cszAccount, DEFAULT_TUNNEL_USERNAME, nAccountMaxLength - 1);        cszAccount[nAccountMaxLength - 1] = '\0';        strncpy(cszPassword, DEFAULT_TUNNEL_PASSWORD, nPasswordMaxLength - 1);        cszPassword[nPasswordMaxLength - 1] = '\0';    } }
關(guān)鍵說明:通過 pArg 傳遞設(shè)備專屬信息,實(shí)現(xiàn)多設(shè)備差異化認(rèn)證(不同設(shè)備可使用不同賬號密碼)。
(三)端口映射(核心步驟)
1. 建立本地端口與設(shè)備端口的映射

將 APP 本地端口與設(shè)備端服務(wù)端口綁定,APP 訪問本地端口即可穿透至設(shè)備端對應(yīng)服務(wù)(如本地10001→設(shè)備22端口(SSH))。

/** * 建立P2P隧道端口映射 * @param SID 已建立的P2P會話ID(連接成功返回的SID) * @param local_port APP本地端口(自定義,需未被占用) * @param remote_port 設(shè)備端服務(wù)端口(如SSH=22、HTTP=80、RTSP=554) * @return 映射索引(>=0成功,<0失敗) */ // 示例:映射本地10001端口 → 設(shè)備22端口(SSH服務(wù)) int local_port = 10001; int remote_port = 22; int mapIndex = P2PTunnelAgent_PortMapping(SID, local_port, remote_port); // 處理映射結(jié)果 if (mapIndex < 0) {    // 映射失?。狠敵鲈敿?xì)信息(常見原因:本地端口被占用、SID無效)    printf("端口映射失敗 - SID: %d, 本地端口: %d → 設(shè)備端口: %d, 錯誤碼: %d\n",           SID, local_port, remote_port, mapIndex);        // 解決方案:本地端口被占用時,更換本地端口(如10002、10003)    local_port = 10002;    mapIndex = P2PTunnelAgent_PortMapping(SID, local_port, remote_port);    if (mapIndex >= 0) {        printf("更換本地端口后映射成功 - 本地端口: %d → 設(shè)備端口: %d, 映射索引: %d\n",               local_port, remote_port, mapIndex);    } } else {    // 映射成功:記錄映射索引(后續(xù)解除映射需使用)    printf("端口映射成功 - SID: %d, 本地端口: %d → 設(shè)備端口: %d, 映射索引: %d\n",           SID, local_port, remote_port, mapIndex);        // 提示:APP可通過訪問 127.0.0.1:%d 訪問設(shè)備服務(wù)(如127.0.0.1:10001)    printf("訪問方式:127.0.0.1:%d(等同于訪問設(shè)備端 %d 端口)\n", local_port, remote_port); }

重要提醒

端口映射成功后,需妥善保存 mapIndex(映射索引),后續(xù)解除映射必須使用該索引,否則會導(dǎo)致本地端口長期占用。

2. 多設(shè)備端口映射示例

若 APP 需連接多個設(shè)備,通過不同本地端口區(qū)分,實(shí)現(xiàn)同時訪問多個設(shè)備的同一服務(wù)端口。

// 多設(shè)備端口映射示例(3臺設(shè)備,均訪問80端口(HTTP服務(wù))) sTunnelInfo multiDeviceInfo[3] = {    {.uid = "DEVICE_UID_001", .username = "user1", .password = "pass1"},    {.uid = "DEVICE_UID_002", .username = "user2", .password = "pass2"},    {.uid = "DEVICE_UID_003", .username = "user3", .password = "pass3"} }; int deviceSIDs[3] = {0};         // 存儲3臺設(shè)備的SID int deviceMapIndexes[3] = {0};   // 存儲3臺設(shè)備的映射索引 int localPorts[3] = {10001, 10002, 10003}; // 3個不同本地端口 int remotePort = 80;             // 設(shè)備端HTTP服務(wù)端口 // 循環(huán)建立多設(shè)備連接和映射 for (int i = 0; i < 3; i++) {    // 建立P2P連接(復(fù)用之前的連接邏輯)    deviceSIDs[i] = P2PTunnelAgent_Connect_Ex(        multiDeviceInfo[i].uid,        TunnelClientAuthentication,        (void*)&multiDeviceInfo[i]    );    if (deviceSIDs[i] < 0) {        printf("設(shè)備%d(UID:%s)連接失敗\n", i+1, multiDeviceInfo[i].uid);        continue;    }    // 建立端口映射    deviceMapIndexes[i] = P2PTunnelAgent_PortMapping(deviceSIDs[i], localPorts[i], remotePort);    if (deviceMapIndexes[i] >= 0) {        printf("設(shè)備%d映射成功 - 訪問 127.0.0.1:%d → 設(shè)備%d的80端口\n",               i+1, localPorts[i], i+1);    } }
說明:多設(shè)備場景下,通過“不同本地端口+不同SID+不同映射索引”實(shí)現(xiàn)區(qū)分,APP 訪問對應(yīng)本地端口即可定位到目標(biāo)設(shè)備。
(四)解除端口映射(必選,避免端口占用)
1. 單個映射解除

不需要訪問設(shè)備服務(wù)時,需及時解除端口映射,釋放本地端口資源。

// 通過映射索引解除單個端口映射(mapIndex為映射成功時返回的索引) P2PTunnelAgent_StopPortMapping(mapIndex); printf("已解除映射索引%d對應(yīng)的端口映射\n", mapIndex);
2. 多個映射批量解除

多設(shè)備場景下,可通過索引數(shù)組批量解除多個端口映射,簡化操作。

// 批量解除多個端口映射(示例:解除3個設(shè)備的映射) int mapIndexArray[3] = {deviceMapIndexes[0], deviceMapIndexes[1], deviceMapIndexes[2]}; // 調(diào)用批量解除接口(參數(shù):映射索引數(shù)組,數(shù)組長度) P2PTunnelAgent_StopPortMapping_byIndexArray(mapIndexArray, 3); printf("已批量解除3個端口映射\n");

注意

斷開設(shè)備連接前,必須先解除所有端口映射,否則會導(dǎo)致本地端口無法釋放,后續(xù)無法重復(fù)使用該端口。

(五)斷開 P2P 連接(必選)
1. 優(yōu)雅斷開(推薦)

等待緩沖區(qū)數(shù)據(jù)發(fā)送完成后再斷開連接,避免數(shù)據(jù)丟失(適用于文件傳輸、數(shù)據(jù)同步等場景)。

// 優(yōu)雅斷開連接(參數(shù):會話ID SID) P2PTunnelAgent_Disconnect(SID); printf("已優(yōu)雅斷開SID=%d的P2P連接(等待數(shù)據(jù)發(fā)送完成)\n", SID);
2. 強(qiáng)制斷開

不等待數(shù)據(jù)發(fā)送,直接斷開連接(適用于緊急退出、網(wǎng)絡(luò)異常等場景)。

// 強(qiáng)制斷開連接(參數(shù):會話ID SID) P2PTunnelAgent_Abort(SID); printf("已強(qiáng)制斷開SID=%d的P2P連接(不等待數(shù)據(jù)發(fā)送)\n", SID);
說明:兩種方式任選其一,建議優(yōu)先使用優(yōu)雅斷開(P2PTunnelAgent_Disconnect),確保數(shù)據(jù)完整性。
(六)Agent 反初始化(必選)
1. 釋放 Agent 資源

APP 退出時,調(diào)用反初始化接口釋放 P2PTunnel Agent 模塊的所有資源,避免內(nèi)存泄漏。

// Agent 反初始化(APP退出時僅需調(diào)用一次) P2PTunnelAgentDeInitialize(); printf("P2PTunnel Agent 反初始化完成\n");
說明:反初始化前需確保所有端口映射已解除、所有 P2P 連接已斷開,否則可能導(dǎo)致資源釋放不徹底。

三、常見問題

問:如果本地端口被占用了,該如何處理?

答:換一個未被占用的本地端口即可。建議 APP 內(nèi)置端口檢測邏輯(如嘗試10001→10002→10003...),自動選擇可用端口。


問:如果 Agent 需要連接多個設(shè)備,該如何區(qū)分不同的設(shè)備?

答:通過不同的本地端口區(qū)分。例如:3臺設(shè)備均提供 HTTP 服務(wù)(80端口),APP 可使用 10001、10002、10003 分別映射這3臺設(shè)備的80端口,訪問對應(yīng)本地端口即可定位到目標(biāo)設(shè)備。同時,通過 SID(會話ID)和映射索引分別管理不同設(shè)備的連接和映射。


問:P2PTunnelAPIs 可以使用 IOTCAPIs 的 API 嗎?

答:可以,調(diào)用 IOTCAPIs 接口時,傳入 P2P 會話的 SID(連接成功返回的會話ID)即可,數(shù)據(jù)會通過 P2P 隧道傳輸。


問:P2PTunnelAPIs 可以與其他模塊(AV、RDT)一起使用嗎?

答:可以,但集成復(fù)雜度較高,容易出現(xiàn)資源沖突或兼容性問題,通常不建議混合使用。若需同時實(shí)現(xiàn)音視頻傳輸和隧道功能,建議優(yōu)先使用 P2PTunnel 承載音視頻 TCP 流。

即刻開啟您的物聯(lián)網(wǎng)之旅

聯(lián)系解決方案專家
Kalay App
資訊安全白皮書
全球?qū)@季?/a>
解決方案
新聞動態(tài)
公司動態(tài)
行業(yè)資訊
媒體報道
永續(xù)發(fā)展
經(jīng)營者的話
社會參與
環(huán)境永續(xù)
公司治理

+86 755 27702549

7×24小時服務(wù)熱線

法律聲明 隱私權(quán)條款

關(guān)注“TUTK”

TUTK服務(wù)盡在掌握

? 2022 物聯(lián)智慧科技(深圳)有限公司版權(quán)所有粵ICP備14023641號
在線咨詢
掃一掃

TUTK服務(wù)盡在掌握

全國免費(fèi)服務(wù)熱線
+86 755 27702549

返回頂部