Sipdroid實現SIP(六): SIP中的請求超時和重傳


目錄

一. Sipdroid的請求超時和重傳

二. SIP中超時和重傳的定義

三. RFC中超時和重傳的定義


 

一. Sipdroid的請求超時和重傳

Sipdroid實現SIP協議棧系列, 之前的文章僅涉及了SIP消息的基本概念, 比如:

  • 請求型消息: INVITE, REGISTER...
  • 應答型消息: 100 Trying, 180 Ringing, 200 OK, BYE, ACK...
  • 攜帶SDP信息
  • 攜帶認證信息

這篇文章更深入一些, 介紹了SIP作為一種可靠傳輸, 涉及到的超時和重傳機制. 也是在調試bug時發現的新大陸.

1.1 出現的問題

注冊在同一個SIP Server的兩個SIP Client互相呼叫時, 會話建立前的SIP信令一切正常, 雙發也開始響鈴, 但是被叫5s內不接聽或拒接, 主叫就會發送CANCEL, 被叫就會回復100 Trying + 487 + 200 OK, 然后會話中斷. 也就是響鈴時間只有5s, 主叫就取消了呼叫.

1.2 初步推測

  • 被叫回復的100 Trying和180 Ringing都沒有收到? 
  • 服務器轉發的被叫回復的100 Trying和180 Ringing都沒有收到? 
  • 主叫的代碼里是否有修改響鈴時間的參數? 
  • 主叫本地有什么超時CANCEL的機制被魔法般地啟動了?

1.3 解決方法

從主叫對象ua開始追蹤基類: UA->InviteDialog->InviteTransactionClient, 發現在發送各類請求msg前有一個線程類InnerTimer對象的啟動, 這個線程的休眠時間, 就是響鈴時間.

1.4 問題原因

Sipdroid的請求超時參數設置錯誤. RFC推薦的32000被設置成5000, 導致INVITE請求在5s內沒有收到200 OK回執, 就被視為超時, 主叫主動CANCEL了呼叫請求.  要修改的代碼在SipStack類里, 該類描述了SIP協議棧的一些基本屬性, 包括SIP默認使用端口, 默認傳輸協議, 默認超時時間等. 修改參數如下:

    /**
     * starting retransmission timeout (milliseconds); called T1 in RFC2361;
     * they suggest T1=500ms
     */
    public static long retransmission_timeout = 2000;
    
    /**
     * maximum retransmission timeout (milliseconds); called T2 in RFC2361; they
     * suggest T2=4sec
     */
    public static long max_retransmission_timeout = 16000;
    
    /** transaction timeout (milliseconds); RFC2361 suggests 64*T1=32000ms */
    //public static long transaction_timeout = 5000;[CHG]這里應該修改為RFC推薦值            
    public static long transaction_timeout = 32000;
    
    /** clearing timeout (milliseconds); T4 in RFC2361; they suggest T4=5sec */
    public static long clearing_timeout = 5000;

 

 


 

 

 

一直知道TCP協議里有重傳算法, 確保了傳輸可靠性, 而且是應用層基本無法質疑的可靠. 

 

在有超時機制的msg發送前,  初始化類對象, 它們一般會被命名為transaction

 

class InnerTimer extends Thread {
    long timeout;
    InnerTimerListener listener;

    public InnerTimer(long timeout, InnerTimerListener listener) {
        this.timeout = timeout;
        this.listener = listener;
        start();
    }

    public void run() {
        if (listener != null) {
            try {
                Thread.sleep(timeout);
                listener.onInnerTimeout();
            } catch (Exception e) {

                e.printStackTrace();
            }
            listener = null;
        }
    }
}

 

 

 

class InnerTimerST extends java.util.TimerTask {
    static java.util.Timer single_timer = new java.util.Timer(true);

    // long timeout;
    InnerTimerListener listener;

    public InnerTimerST(long timeout, InnerTimerListener listener) { // this.timeout=timeout;
        this.listener = listener;
        single_timer.schedule(this, timeout);
    }

    public void run() {
        if (listener != null) {
            listener.onInnerTimeout();
            listener = null;
        }
    }
}

 

 

 

參考

[1] [SIP協議]學習初學筆記

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM