日韩美女乱婬AAA高清视频_国产色爱AV资源综合区_国产女同性黄网在线观看_欧美日韩一卡2卡3卡4卡新区乱码_俺来也俺也啪www色_精品久久久久久综合日本_99国内偷揿国产精品人妻_国产蜜芽剧果冻传媒_日本特级aaaaaaaa片_国产偷人妻精品一区二区在线

簡(jiǎn)體中文

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

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

一、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è)備連接場(chǎng)景。

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

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

// 設(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; }
說(shuō)明:sdk_license_key 需妥善保管,避免泄露;APP 啟動(dòng)時(shí)僅需調(diào)用一次。
2. 初始化 P2PTunnel Agent 模塊

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

// 定義最大支持的設(shè)備連接數(shù)(自定義,如8臺(tái)設(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
說(shuō)明:初始化接口僅需在 APP 啟動(dòng)時(shí)調(diào)用一次,多次調(diào)用可能導(dǎo)致資源沖突。
3. 注冊(cè)隧道狀態(tài)回調(diào)函數(shù)

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

// 注冊(cè)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);
說(shuō)明:TunnelStatusCB 需按 SDK 定義的函數(shù)原型實(shí)現(xiàn),示例:void TunnelStatusCB(int SID, int status, void* pArg),其中 SID 為會(huì)話ID,status 為狀態(tài)碼。
(二)建立 P2P 隧道連接(必選)
1. 調(diào)用擴(kuò)展連接接口

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

// 設(shè)備信息結(jié)構(gòu)體(存儲(chǔ)設(shè)備UID、認(rèn)證信息等,自定義) typedef struct {    char uid[64];          // 設(shè)備唯一標(biāo)識(shí)(由設(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è)密碼 }; // 嘗試通過(guò)新版本擴(kuò)展接口建立P2P隧道連接 int SID = P2PTunnelAgent_Connect_Ex(    tunnelInfo.uid,                  // 目標(biāo)設(shè)備UID    TunnelClientAuthentication,      // 客戶端認(rèn)證回調(diào)函數(shù)(填充賬號(hào)密碼)    (void*)&tunnelInfo               // 自定義參數(shù)(傳遞設(shè)備信息給回調(diào)) ); // 處理"遠(yuǎn)程不支持DTLS"錯(cuò)誤(舊版本設(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};        // 自動(dòng)初始化緩沖區(qū)為0    int nDeviceErr = 0;              // 接收設(shè)備端返回的錯(cuò)誤碼    // 填充舊版本默認(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ù)長(zhǎng)度        &nDeviceErr                  // 輸出設(shè)備端錯(cuò)誤碼(便于排查)    );    // 打印舊版本連接結(jié)果    printf("舊版本接口連接結(jié)果 - UID: %s, 會(huì)話ID(SID): %d, 設(shè)備錯(cuò)誤碼: %d\n",           tunnelInfo.uid, SID, nDeviceErr); } // 處理最終連接結(jié)果 if (SID < 0) {    printf("P2P連接失敗,錯(cuò)誤碼: %d(參考SDK文檔錯(cuò)誤碼說(shuō)明)\n", SID);    return -1; } else {    printf("P2P連接成功,會(huì)話ID(SID): %d(后續(xù)操作需使用該SID)\n", SID); }
說(shuō)明:連接成功后返回的 SID 為會(huì)話唯一標(biāo)識(shí),后續(xù)端口映射、斷開連接等操作需傳入該 SID。
2. 實(shí)現(xiàn)客戶端認(rèn)證回調(diào)函數(shù)

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

/** * 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ū)最大長(zhǎng)度(含字符串終止符'\0') * @param cszPassword 輸出參數(shù):密碼緩沖區(qū)(SDK讀取該緩沖區(qū)進(jìn)行認(rèn)證) * @param nPasswordMaxLength cszPassword緩沖區(qū)最大長(zhǎng)度(含字符串終止符'\0') * @param pArg 自定義參數(shù):傳遞的sTunnelInfo結(jié)構(gòu)體指針(區(qū)分不同設(shè)備) */ // 全局默認(rèn)認(rèn)證信息(適用于無(wú)自定義信息的設(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] 無(wú)效參數(shù):緩沖區(qū)為空或長(zhǎng)度為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 {        // 無(wú)自定義設(shè)備信息:使用全局默認(rèn)認(rèn)證信息        printf("[%s] 無(wú)設(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)鍵說(shuō)明:通過(guò) pArg 傳遞設(shè)備專屬信息,實(shí)現(xiàn)多設(shè)備差異化認(rèn)證(不同設(shè)備可使用不同賬號(hào)密碼)。
(三)端口映射(核心步驟)
1. 建立本地端口與設(shè)備端口的映射

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

/** * 建立P2P隧道端口映射 * @param SID 已建立的P2P會(huì)話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無(wú)效)    printf("端口映射失敗 - SID: %d, 本地端口: %d → 設(shè)備端口: %d, 錯(cuò)誤碼: %d\n",           SID, local_port, remote_port, mapIndex);        // 解決方案:本地端口被占用時(shí),更換本地端口(如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可通過(guò)訪問(wèn) 127.0.0.1:%d 訪問(wèn)設(shè)備服務(wù)(如127.0.0.1:10001)    printf("訪問(wèn)方式:127.0.0.1:%d(等同于訪問(wèn)設(shè)備端 %d 端口)\n", local_port, remote_port); }

重要提醒

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

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

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

// 多設(shè)備端口映射示例(3臺(tái)設(shè)備,均訪問(wèn)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};         // 存儲(chǔ)3臺(tái)設(shè)備的SID int deviceMapIndexes[3] = {0};   // 存儲(chǔ)3臺(tái)設(shè)備的映射索引 int localPorts[3] = {10001, 10002, 10003}; // 3個(gè)不同本地端口 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映射成功 - 訪問(wèn) 127.0.0.1:%d → 設(shè)備%d的80端口\n",               i+1, localPorts[i], i+1);    } }
說(shuō)明:多設(shè)備場(chǎng)景下,通過(guò)“不同本地端口+不同SID+不同映射索引”實(shí)現(xiàn)區(qū)分,APP 訪問(wèn)對(duì)應(yīng)本地端口即可定位到目標(biāo)設(shè)備。
(四)解除端口映射(必選,避免端口占用)
1. 單個(gè)映射解除

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

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

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

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

注意

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

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

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

// 優(yōu)雅斷開連接(參數(shù):會(huì)話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ò)異常等場(chǎng)景)。

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

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

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

三、常見問(wèn)題

問(wèn):如果本地端口被占用了,該如何處理?

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


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

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


問(wèn):P2PTunnelAPIs 可以使用 IOTCAPIs 的 API 嗎?

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


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

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

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

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

+86 755 27702549

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

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

關(guān)注“TUTK”

TUTK服務(wù)盡在掌握

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

TUTK服務(wù)盡在掌握

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

返回頂部