首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> C++ 入門

基於 GB/T 28181 的 SIP 協議組件開發:eXosip2 實現 SIP 註冊流程(二)

     編輯:C++ 入門

前言

本文承接上一篇,繼續探討基於 GB/T 28181 標準的 SIP 協議組件開發,重點講解如何使用 eXosip2 庫實現 UAC(用戶代理客戶端)的註冊、刷新註冊及註銷流程。上一篇已介紹註冊的理論基礎與 Demo 程序框架,本節將深入剖析核心 API 調用、事件處理機制及完整代碼實現,並通過實測驗證流程正確性。

一、eXosip2 核心 API 介紹

1.1 庫初始化與監聽

使用 eXosip2 前,必須先初始化協議棧環境並綁定監聽地址。初始化失敗將導致後續操作無法進行。

#include <eXosip2/eXosip.h>
int result = OSIP_SUCCESS;
// 初始化庫
if (OSIP_SUCCESS != (result = eXosip_init())) {
    printf("eXosip_init failure.\n");
    return 1;
}
cout << "eXosip_init success." << endl;
// 監聽 UDP 端口
if (OSIP_SUCCESS != eXosip_listen_addr(IPPROTO_UDP, NULL, UACPORTINT, AF_INET, 0)) {
    printf("eXosip_listen_addr failure.\n");
    eXosip_quit();
    return 1;
}

初始化完成後,即可發送 SIP 消息並等待接收事件。

1.2 事件循環與默認處理

主循環中調用 eXosip_event_wait 獲取事件,並使用 eXosip_default_action 自動處理 401/407 鑑權回應,這是實現註冊重試的關鍵。

eXosip_event_t* osipEventPtr = NULL;
while (true) {
    osipEventPtr = ::eXosip_event_wait(0, 200);
    eXosip_lock();
    eXosip_default_action(osipEventPtr); // 自動處理鑑權
    eXosip_unlock();
    if (NULL == osipEventPtr) continue;
    // 根據事件類型分發處理...
    eXosip_event_free(osipEventPtr);
    osipEventPtr = NULL;
}

註:實際生產環境建議採用線程池併發處理事件,避免長耗時操作阻塞主循環。

1.3 SIP 消息解析

從事件中提取請求/響應報文,解析頭部字段(如 Expires)以獲取業務參數。

osip_header_t* header = NULL;
osip_message_header_get_byname(request, "expires", 0, &header);
if (NULL != header && NULL != header->hvalue) {
    // 解析 expires 值
}

二、UAC 註冊完整實現

2.1 關鍵數據結構

定義了 CSipFromToHeader 和 CContractHeader 類,封裝 From/To/Contact 頭部的生成邏輯,確保格式符合 SIP 標準。

2.2 統一發送接口 SendRegister

該函數根據 iType 參數(0:初始註冊, 1:刷新, 2:註銷)構建並發送 REGISTER 請求。關鍵點:

  • 首次註冊調用 eXosip_register_build_initial_register 獲取註冊 ID;
  • 後續刷新/註銷調用 eXosip_register_build_register 復用該 ID;
  • 註銷時設置 expires=0 並添加 Logout-Reason 頭部;
  • 發送前通過 eXosip_add_authentication_info 預置憑證,鑑權由庫自動完成。
int SendRegister(int& registerId, CSipFromToHeader &from, CSipFromToHeader &to,
                 CContractHeader &contact, const string& userName, const string& pwd,
                 const int expires, int iType) {
    // ... 參數打印省略 ...
    static osip_message_t *regMsg = 0;
    int ret;
    ::eXosip_add_authentication_info(userName.c_str(), userName.c_str(), pwd.c_str(), "MD5", NULL);
    eXosip_lock();
    if (0 == registerId) {
        registerId = ::eXosip_register_build_initial_register(
            from.GetFormatHeader().c_str(), to.GetFormatHeader().c_str(),
            contact.GetContractFormatHeader().c_str(), expires, &regMsg);
        if (registerId <= 0) return -1;
    } else {
        ret = ::eXosip_register_build_register(registerId, expires, &regMsg);
        if (ret != OSIP_SUCCESS) return ret;
        if (expires == 0) {
            // 修改 Contact 頭部並添加註銷原因
            osip_contact_t *contact = NULL;
            char tmp[128];
            osip_message_get_contact(regMsg, 0, &contact);
            sprintf(tmp, "<sip:%s@%s:%s>;expires=0",
                    contact->url->username, contact->url->host, contact->url->port);
            osip_list_remove(&regMsg->contacts, 0);
            osip_message_set_contact(regMsg, tmp);
            osip_message_set_header(regMsg, "Logout-Reason", "logout");
        }
    }
    ret = ::eXosip_register_send_register(registerId, regMsg);
    if (ret != OSIP_SUCCESS) registerId = 0;
    eXosip_unlock();
    return ret;
}

2.3 業務邏輯封裝

Register()、RefreshRegister()、UnRegister() 三個函數分別對應用戶操作,內部調用 SendRegister 並維護狀態變量 iCurrentStatus 和 iHandle。

2.4 事件處理線程

將事件分發到獨立線程處理,主循環僅負責接收與分發,提高併發能力。示例中處理 EXOSIP_REGISTRATION_SUCCESS 和 EXOSIP_REGISTRATION_FAILURE 事件,打印狀態碼與處理結果。

三、測試驗證

3.1 程序啟動

啟動介面

3.2 執行註冊 (輸入 0)

觀察到流程:發送 REGISTER → 收到 401 Unauthorized → 庫自動發送帶憑證的 REGISTER → 收到 200 OK。
註冊過程

3.3 刷新註冊 (輸入 1)

直接收到 200 OK,無鑑權挑戰。
刷新註冊

3.4 註銷 (輸入 2)

發送 expires=0 的 REGISTER,收到 200 OK,Contact 頭部顯示 expires=0。
註銷過程

總結

本文完整展示了基於 eXosip2 實現 SIP 註冊全生命周期的方法,關鍵在於正確使用 eXosip_default_action 讓庫自動處理摘要鑑權,並妥善管理註冊 ID 與狀態機。代碼結構清晰,可直接作為 GB/T 28181 設備接入開發的參考基礎。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved