1. 程式人生 > >PJSIP開發手冊之傳輸層(六)

PJSIP開發手冊之傳輸層(六)

第六章 傳輸層

Transport是用來通過網路傳送/接收訊息的。PJSIPtransport框架是可擴充套件的,這意味著程式可以自己的transport來傳輸訊息。

傳輸層設計

類圖

下圖展示了transport層的各個例項之間的關係。


Transport Manager

Transport Manager(pjsip_tpmgr管理所有的transport物件和工廠。它提供以下功能:

  • 通過使用引用計數器和空閒的定時器管理transport的生命週期
  • 管理transport工廠
  • 從transport接收包,解析包並把SIP訊息傳給Endpoint
  • 基於transport的型別和遠端的地址,找到匹配的transport
    來給指定地點發送SIP訊息
  • 當不存在可用的transport來發送SIP訊息時,動態建立transport

每個Endpoint只有一個transport manager。Transport manager通常是應用不可見的,應用需要使用Endpoint提供的函式。

Transport工廠

Transport工廠(pjsip_tpfactory是用來建立與遠端Endpoint的連線。這種型別的連線的一個例子就是TCP transport。每個目的地址需要建立一個TCP transport

當transport manager測到它需要為新的地址建立新的transport,它將會找到符合的transport

工廠,並讓工廠建立一個連線。

Transport

Transport物件用pjsip_transport結構表示。每個例項代表一個socket處理(如UDPTCP,但是transport層也支援non-socket的傳輸。

通用的transport操作

從框架角度來看,transport物件是一個活動的物件。框架中並不存在輪詢transport物件的機制。因此傳輸物件必須找到自己的方式來從網路上接收資料包,以及將資料包提交到transport manager為之後的處理

推薦的實現方法是將transportsocket處理註冊到EndpointI/O佇列pj_ioqueue_t)。因此,當Endpoint

輪詢I/O佇列,網路上的包將被transport物件接收。

一旦transport物件接收了一個包,它必須呼叫pjsip_tpmgr_receiver_packet()函式將這個包傳給transport manager,這樣這個包將被解析並分發到棧剩下的部分。Transport物件必須初始化接收資料快取tp_infopkt_info

每個transport物件有一個指向傳送訊息到網路上的函式指標(如send_msg()。應用(或棧)向網路傳送訊息通過呼叫pjsip_transport_send()函式,這個函式最終也會呼叫各個transport物件的send_msg()函式。傳送包可以非同步完成,transport物件的send_msg()必須返回PJ_EPENDING,並且當訊息到達目的地時,呼叫引數內指定的回撥函式。

Transport物件宣告

下面程式碼展示了transport物件的宣告。


Transport管理

通過呼叫pisip_transport_register()函式來註冊transporttransport manager。在呼叫此函式前transport結構中的所有成員必須被初始化。

Transport的生命週期由transport manager自動管理。每當transport的引用計數器0,一個空閒定時器將啟動。當空閒的計數器超時時並且引用計數器仍為0transport manager將呼叫pjsip_transport_unregister()來銷燬transport。這個函式將transporttransport manager的雜湊表上登出,並最終銷燬它。

一些transport需要一直存在,即使沒有被使用(如UDP transport,它是一個單例例項)。為了阻止那個transport被刪除,它需要把引用計數器初始設定為1這樣,引用計數器將永不為0

Transport錯誤處理

Transport使用者負責處理transport錯誤(如傳送包失敗或連線重置)。Transport物件自己不需要處理這種錯誤,除了在函式的返回值報出錯誤。特別地,它一定不要嘗試去重連線一個失敗/關閉的連線。

使用transport

函式指南


獲取t_type型別的transport來發送訊息到目的地remote_addr。注意,當transport被成功獲取,這個transport的引用指標將增加


增加transport的引用計數器。這個函式阻止transport被銷燬,並且它可以取消活動的空閒計數器。


減少transport的引用計數器。每當transport的引用計數器0,一個空閒定時器將啟動。當空閒的計數器超時時並且引用計數器仍為0transport manager將呼叫pjsip_transport_unregister()來銷燬transport


傳送tdataremote_addr使用transport。如果函式立刻完成且資料已經發送,則返回PJ_SUCCESS。如果函式立刻完成但有錯誤,則返回一個非0錯誤碼。這兩種情況下,回撥函式都不會被呼叫。

如果函式沒有立刻完成(如當下層socket快取滿),函式將返回PJ_EPENDING,並且呼叫者將通過cb回撥函式被通知。如果待發送的操作完成時有錯誤,則bytes_sent是負值的錯誤碼(使用”pj_status_t status = -bytes_sent”來獲取錯誤碼)。

該函式只會照原樣傳送訊息,不會對訊息做任何驗證。Via頭部域也不會被修改。

擴充套件transports

PJSIP可以擴充套件自定義的transports。理論上,所有型別的transport,不侷限於TCP/IP,都可以加入transport manager的框架中。

初始化transports

PJSIP是預設不會開始任何的transport甚至內建的transport;應用在需要時會被初始化並開始transports

下面是內建的UDPTCP transport的初始化。

UDP transport初始化

PJSIP提供兩種選擇去建立、初始化和開始UDP transports。下面函式宣告在<pjsip/sip_transport_udp.h>中:


建立,初始化,註冊和開始一個新的UDP transportUDP socket將被繫結到local_addr。如果Endpoint位於防火牆/NAT埠轉發裝置後面,那麼pub_addr可以用作此transport物件的公共地址;否則pub_addr應該與local_addr相同。引數async_cnt指定這個transport物件可以允許有多少個併發操作,為了效能最大化,這個引數應該等於節點的處理器數。


如果transport物件啟動成功,函式返回PJ_SUCCESS,且傳輸物件返回到p_transport引數中。應用可以立刻使用這個transport物件,而不需要向transport manager註冊,因為這個函式返回成功時,就已註冊過了。

關於錯誤,函式將返回一個非0錯誤碼。


在UDP socket已經可用的情況下建立、初始化、註冊和啟動一個新的UDP transport物件。這個函式在如下的情況下非常有用,當應用已使用了STUN解析了socket的公共地址,這時可以不用關閉它後再重新建立一個新的socket,而是可以直接重用此socket

TCP transpor初始化

待做

TLS transport初始化

待做

SCTP transport初始化

待做