• 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协议]学习初学笔记

  • 相关阅读:
    操作系统
    Typora
    C++
    linux sftp 和scp 运用
    python GIL锁与多cpu
    django model 高级进阶
    django template 模板
    django view 视图控制之数据返回的视图函数
    django 创建管理员用户
    jango 模型管理数据model入门
  • 原文地址:https://www.cnblogs.com/elsarong/p/6246075.html
Copyright © 2020-2023  润新知