zoukankan      html  css  js  c++  java
  • oSIP协议栈浅析


     
     
     


     
    1. oSIP介绍
        oSIP是按照RFC3261(SIP)和RFC2327(SDP)标准,并使用标准c编写的一个SIP协议栈。它是一个公开源码的免费协议栈。oSIP协议栈结构简单而小巧,它并不提供高层的SIP会话控制的API,它主要提供一些解析SIP/SDP消息的API和事务处理的状态机。
    oSIP支持线程安全,既可以用于多线程的编程模式,也可以用于单线程的编程模式;oSIP可以用来开发User Agent,IP soft-phone和SIP Proxy等等。
    oSIP目前最后版本为V 0.9.7,不久oSIP版本将升级至oSIP2(V 1.99.7)。oSIP2主要调整了一些函数和结构名称,以及一些头文件的名称、内容结构的调整,整体的构架和功能不变。
    本文以下描述都基于oSIP V0.9.6版本。
     
     
    2. oSIP结构分析
    2.1 oSIP结构
        oSIP主要包括三大部分的内容:状态机模块、解析器模块和工具模块。
        状态机模块的功能
    完成对某个事务(注册过程,呼叫过程等等)状态记录,并在特定状态下触发相应的事件或回调函数。
        解析器模块的功能
           该模块主要完成对SIP消息结构剖析、SDP消息的结构剖析以及URI结构的剖析;
        工具模块的功能
           该模块提供一些SDP等处理的一些工具。
     
           oSIP的模块结构图如下(图2-1):


     

    SIP parser
    URL parser
    SDP parser
    Finite
    State
    Machines
    Dialogue Facilities
    SDP negotiation
    Facilities
    Application
    状态机模块
    解析器模块
    工具模块(可选项)
    oSIP模块
    图2-1 oSIP结构
     

     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     


    2.2 状态机(Finite State Machines)模块
    2.2.1 概述
        oSIP状态机(Finite State Machines)主要分为四类,分别为:
    Ø        ICT    -- Invite Client (outgoing) Transaction
    Ø        NICT   -- Non-Invite Client (outgoing) Transaction
    Ø        IST    -- Invite Server (incoming) Transaction
    Ø        NIST   -- Non-Invite Server (incoming) Transaction
     


     
    2.2.2 ICT状态机
     

    ICT_PRE_CALLING
    ICT_COMPLETED
    ICT_PROCEEDING
    ICT_TERMINATED
    Transaction initialization
    ICT_CALLING
    cb_ict_transport_error
    cb_ict_invite_sent
    cb_ict_invite_sent2
    cb_ict_transport_error
    图 2-2: ICT State Machine
    cb_ict_kill_transaction
    cb_ict_transport_error
    cb_ict_1xx_received
    cb_ict_2xx_received
    cb_ict_transport_error
    cb_ict_1xx_received
    cb_ict_Nxx_received
    cb_ict_Nxx_received
    cb_ict_3456xx_received2
    cb_ict_ack_sent2
     

     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     


    cb_ict_xxx_xxxx
    表示从一种状态转换到另一种状态时将调用该回调函数
    表示从一种状态转换到另一种状态时不调用任何回调函数
    注:

          
     
     
     
     
    cb_ict_Nxx_received:其中N表示一下几个值
           3            --     cb_ict_3xx_received
           4            --     cb_ict_4xx_received
           5            --     cb_ict_5xx_received
           6            --     cb_ict_6xx_received
     


     
    2.2.3 NICT状态机
     

    NICT_PRE_TRYING
    NICT_COMPLETED
    NICT_PROCEEDING
    NICT_TERMINATED
    Transaction initialization
    NICT_TRYING
    cb_nict_transport_error
    cb_nict_XXX_sent
    cb_nict_request_sent2
    cb_nict_1xx_received
    图2-3: NICT State Machine
    cb_nict_Nxx_received
    cb_nict_kill_transaction
    cb_nict_transport_error
    cb_nict_request_sent2
    cb_nict_1xx_received
    cb_nict_Nxx_received
    cb_nict_transport_error
     

     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     


    cb_nict_xxx_xxxx
    表示从一种状态转换到另一种状态时将调用该回调函数
    表示从一种状态转换到另一种状态时不调用任何回调函数
    注:

     
     
     
     
    cb_nict_XXX_sent:其中XXX表示一下几种消息类型,
    register  --     cb_nict_register_sent
    bye         --     cb_nict_bye_sent
    options  --     cb_nict_options_sent
    info         --     cb_nict_info_sent
    cancel    --     cb_nict_cancel_sent
    notify      --     cb_nict_notify_sent
    subscribe --     cb_nict_subscribe_sent
    unknown --     cb_nict_unknown_sent
     
    cb_nict_Nxx_received:其中N表示一下几个值
           2            --     cb_nict_2xx_received
           3            --     cb_nict_3xx_received
           4            --     cb_nict_4xx_received
           5            --     cb_nict_5xx_received
           6            --     cb_nict_6xx_received
     
     
    2.2.4 IST状态机
     

    IST_PRE_PROCEEDING
    IST_CONFIRMED
    IST_COMPLETED
    IST_TERMINATED
    Transaction initialization
    IST_PROCEEDING
    cb_ist_invite_received
    cb_ist_Nxx_sent
    图2-4: IST State Machine
    cb_ist_ack_received
    cb_ist_1xx_sent
    cb_ist_transport_error
    cb_ist_2xx_sent
    cb_ist_ack_received2
    cb_ist_3456xx_sent2
    cb_ist_invite_received2
    cb_ist_kill_transaction
    cb_ist_transport_error
     

     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     


    cb_ist_xxx_xxxx
    表示从一种状态转换到另一种状态时将调用该回调函数
    表示从一种状态转换到另一种状态时不调用任何回调函数
    注:

     
     
     
     
    cb_ist_Nxx_sent:其中N表示一下几个值,
    3            --     cb_ist_3xx_sent
    4            --     cb_ist_4xx_sent
    5            --     cb_ist_5xx_sent
    6            --     cb_ist_6xx_sent


     
    2.2.5 NIST状态机

    NIST_PRE_TRYING
    NIST_COMPLETED
    NIST_PROCEEDING
    NIST_TERMINATED
    Transaction initialization
    NIST_TRYING
    cb_nist_XXX_ received
    cb_nist_1xx_sent
    图2-5: NIST State Machine
    cb_nist_Nxx_sent
    cb_nist_kill_transaction
    cb_nist_transport_error
    cb_nist_1xx_sent
    cb_nist_Nxx_sent
    cb_nist_transport_error
    cb_nist_request_received2
    cb_nist_request_received2
     

     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     


    cb_nist_xxx_xxxx
    表示从一种状态转换到另一种状态时将调用该回调函数
    表示从一种状态转换到另一种状态时不调用任何回调函数
    注:

     
     
     
     
    cb_nist_XXX_ received:其中XXX表示一下几种消息类型,
    register  --     cb_nist_register_received
    bye         --     cb_nist_bye_received
    options  --     cb_nist_options_received
    info         --     cb_nist_info_received
    cancel    --     cb_nist_cancel_received
    notify      --     cb_nist_notify_received
    subscribe --     cb_nist_subscribe_received
    unknown --     cb_nist_unknown_received
     
    cb_nist_Nxx_ sent:其中N表示一下几个值
           2            --     cb_nist_2xx_sent
           3            --     cb_nist_3xx_sent
           4            --     cb_nist_4xx_sent
           5            --     cb_nist_5xx_sent
           6            --     cb_nist_6xx_sent
     
     
    2.3 解析器(Parsers)模块
           oSIP的SIP Parser处理的SIP头域(SIP Header fields)及其相应的操作功能列表如下:

    SIP Header(头域) Functions(函数名称—简写)  
    Accept set(),get()
    Accept-Encoding
    set(),get(),init(),parse(),2char(),free(),clone()
    Getelement(),setelement()
    Accept-Language set(),get()
    Alert-Info set(),get()
    Allow set(),get()
    Authentication-Info    
    Authorization
    Init(),set(),parse(),get(),getauth_type(),setauth_type(),
    Getusername(),setusername(),getrealm(),setrealm(),
    Getnonce(),setnonce(),geturi(),seturi(),getresponse(),
    Setresponse(),getdigest(),setdigest(),getalgorithm(),
    Setalgorithm(),getcnonce(),setcnonce(),getopaque(),
    Setopaque(),getmessage_qop(),setmessage_qop(),
    getnonce_count(),setnonce_count(),2char(),free(),
    clone()
    Call-ID
    set(),get(),parse(),2char(),free(),clone(),getnumber(),
    setnumber(),gethost(),sethost()
    Call-Info
    set(),get(),init(),parse(),2char(),free(),clone(),
    geturi(),seturi()
    Contact set(),get(),init(),parse(),2char(),free(),clone()
    Content-Disposition set(),get(),parse()
    Content-Encoding set(),get()
    Content-Language    
    Content-Length set(),get(),init(),parse(),2char(),free(),clone()
    Content-Type set(),get(),init(),parse(),2char(),free(),clone()
    CSeq
    set(),get(),init(),parse(),2char(),free(),clone(),
    getnumber(),setnumber(),getmethod(),setmethod()
    Date    
    Error-Info set(),get()
    Expires    
    From
    set(),get(),init(),parse(),2char(),free(),clone(),
    getdisplayname(),setdisplayname(),geturl(),seturl(),
    param_get(),param_parseall(),param_setvalue(),
    param_getvalue(),param_getname(),param_setname(),
    compare()
    In-Reply-To    
    Max-Forwards    
    Min-Expires    
    MIME-Version set(),get()
    Organization    
    Priority    
    Proxy-Authenticate set(),get()
    Proxy-Authorization set(),get()
    Proxy-Require    
    Record-Route set(),get(),init(),parse(),2char(),free()
    Reply-To    
    Require    
    Retry-After    
    Route set(),get(),init(),parse(),2char(),free()
    Server    
    Subject    
    Supported    
    Timestamp    
    To set(),get(),init(),parse(),2char(),free(),clone()
    Unsupported    
    User-Agent    
    Via
    set(),append(),get(),init(),free(),parse(),2char(),
    setversion(),getversion(),setprotocol(),getprotocol(),
    sethost(),gethost(),setport(),getport(),setcomment(),
    getcomment(),clone()
    Warning    
    WWW-Authenticate
    Init(),set(),quoted_string_set(),token_set(),parse(),
    get(),getauth_type(),setauth_type(),getrealm(),setrealm(),
    getdomain(),setdomain(),getnonce(),setnonce(),getstale(),
    setstale(),getopaque(),setopaque(),getalgorithm(),
    setalgorithm(),getqop_options(),setqop_options(),2char(),
    free(),clone()

     
           注:标示“☆”表示oSIP支持该头域(SIP Header fields)解析处理,未注的表示目前还没有解析处理(这些被保存在字符串中,可自行处理分析),可能会在后续版本中逐步补充。
     
     
           SDP的格式一般为:
    <type>=<value>
           type通常为一个英文字母,其取值如下(按照RFC2327,带“*”的表示为可选条目):
    Session description
            v= (protocol version)
            o= (owner/creator and session identifier).
            s= (session name)
            i=* (session information)
            u=* (URI of description)
            e=* (email address)
            p=* (phone number)
            c=* (connection information - not required if included in all media)
            b=* (bandwidth information)
                One or more time descriptions (see below)
            z=* (time zone adjustments)
            k=* (encryption key)
            a=* (zero or more session attribute lines)
                Zero or more media descriptions (see below)
     
    Time description
            t= (time the session is active)
            r=* (zero or more repeat times)
     
    Media description
            m= (media name and transport address)
            i=* (media title)
            c=* (connection information - optional if included at session-level)
            b=* (bandwidth information)
            k=* (encryption key)
            a=* (zero or more media attribute lines)
     
           在oSIP中处理的type和相应操作功能如下:

    type(类型) Functions(函数名称—简写)
    v version_set(),version_get()
    o
    origin_set(),username_get(),sess_id_get(),
    sess_version_get(),nettype_get(),addrtype_get(),
    addr_get()
    s name_set(),name_get()
    i info_set(),info_get()
    u uri_set(),uri_get()
    e email_add(),email_get()
    p phone_add(),phone_get()
    c
    connection_add(),connection_get(),nettype_get(),
    addrtype_get(),addr_get(),addr_multicast_ttl_get(),
    addr_multicast_int_get()
    b bandwidth_add(),bwtype_get(),bandwidth_get()
    t time_descr_add(),start_time_get(),stop_time_get()
    r repeat_add(),repeat_get()
    z adjustments_set(),adjustments_get()
    k key_set(),keytype_get(),keydata_get()
    a attribute_add(),att_field_get(),att_value_get()
    m
    media_add(),media_get(),port_get(),number_of_port_get(),
    proto_get(),payload_add(),payload_get(),

     
        另外,oSIP还包含对SDP包的一些基本操作[set(), get(), init(), parse(), 2char(), free(), clone()],及对各类type的init()和free()操作
     
     
        这里的URL是指SIP中的URI,URI有很多参数格式,在RFC3261中列举了一些比较例子:
       The URIs within each of the following sets are equivalent:
       sip:alice@atlanta.com;transport=TCP
       sip:alice@AtLanTa.CoM;Transport=tcp
     
       sip:carol@chicago.com
       sip:carol@chicago.com;newparam=5
       sip:carol@chicago.com;security=on
     
       sip:biloxi.com;transport=tcp;method=REGISTER?to=sip:bob@biloxi.com
       sip:biloxi.com;method=REGISTER;transport=tcp?to=sip:bob@biloxi.com
     
       sip:alice@atlanta.com?subject=project x&priority=urgent
       sip:alice@atlanta.com?priority=urgent&subject=project x
     
       The URIs within each of the following sets are not equivalent:
     
       SIP:ALICE@AtLanTa.CoM;Transport=udp             (different usernames)
       sip:alice@AtLanTa.CoM;Transport=UDP
     
       sip:bob@biloxi.com                   (can resolve to different ports)
       sip:bob@biloxi.com:5060
     
       sip:bob@biloxi.com              (can resolve to different transports)
       sip:bob@biloxi.com;transport=udp
     
       sip:bob@biloxi.com     (can resolve to different port and transports)
       sip:bob@biloxi.com:6000;transport=tcp
     
       sip:carol@chicago.com                    (different header component)
       sip:carol@chicago.com?Subject=next%20meeting
     
       sip:bob@phone21.boxesbybob.com   (even though that's what
       sip:bob@192.0.2.4                 phone21.boxesbybob.com resolves to)
     
        在oSIP中处理SIP URI有比较多的操作函数提供,主要有对host,port,username,password, scheme的get()和set(),以及对参数的初始化设置和剖析处理。详细函数名称请参考源代码中的url.h。
     
     
    2.4 工具(Facilities)模块
           SDP协商工具(SDP negotiator)帮助end point提供协商codec等功能
     
     
        对话管理工具(Dialog management)是oSIP提供的一个比较强大的辅助工具,主要用于有能力应答呼叫的end point。
        对话管理工具(Dialog management)能够帮助记录请求和响应消息,利用这个工具使end point能够快速准确的作出应答。
     
     
    3. oSIP特点
    3.1 oSIP的优点
    n        Osip没有给开发者限定在特定的某个执行模式下,能够使开发者选定一个比较适合自己的模式。
    n        Osip的各个模块是相对清晰、独立的,因而去掉某个模块时也比较容易。
    n        Osip的解析器提供了较为完善的API,包含了消息的构造、修改和产生等。
     
    3.2 oSIP的缺点
    ¨         oSIP目前版本源代码结构、定义比较混乱,并且缺乏文档,阅读比较困难;该问题将在oSIP2中得到改善。
    ¨         oSIP不提供任何快速产生请求消息和响应消息的方法,所有请求消息和响应消息的形成必须调用一组sip message api来手动组装完成,关于这方面的缺陷,osip作者可能在以后会开发一个eXoSIP的API来完成。
    ¨         由于oSIP结构简单,外围相关模块需要用户自己开发,如SIP消息的接收和发送,RTP/RTCP的语音数据的处理等。
     
    4. oSIP应用结构图
     

    Receive/Send
    SIP Messages
    SIP parser
    URL parser
    SDP parser
    Finite
    State
    Machines
    Dialogue Facilities
    SDP negotiation
    Facilities
     Main thread
    状态机模块
    解析器模块
    工具模块(可选项)
    oSIP模块
    图4-1 oSIP应用
    Receive/Send
    RTP/RTCP
    oSIP
    Instance
    Transaction
    Context
    B
    A
    Application
     

     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     


    其中:
           ①:初始化oSIP和注册CALL BACK函数;
           ②:添加事件A;
           ③:执行事务
           ④:取消事件A
           ⑤:解析消息
           ⑥:触发CALL BACK函数
           ⑦:接收/发送消息
           A:保存状态
           B:接收/发送语音包
     
     
    5. oSIP使用概述
    5.1 初始化oSIP
           在使用oSIP前必须先初始化oSIP,主要调用函数osip_global_init()osip_init(),具体操作代码如下:

    osip_t *osip;
     // initialise internal element first
     if (0!=osip_global_init())
       return -1;
     // allocate a global osip element.
     if (0!=osip_init(&osip))
       return -1;
     

     
     
     
     
     
     
     
     
     


    5.2 注册CALL BACK函数
           需要注册的call back函数主要包含发送消息、结束事务、发送失败、4个状态机(ICT、NICT、IST、NIST)相关函数。
           注册发送消息的CALL BACK函数:

    osip_setcb_send_message(osip, &application_cb_snd_message);
     

     
     


           注册结束事务的CALL BACK函数:

    osip_setcb_ict_kill_transaction(osip,&application_cb_ict_kill_transaction);
    osip_setcb_ist_kill_transaction(osip,&application_cb_ist_kill_transaction);
    osip_setcb_nict_kill_transaction(osip,&application_cb_nict_kill_transaction);
    osip_setcb_nist_kill_transaction(osip,&application_cb_nist_kill_transaction);
     

     
     
     
     
     


           注册发送失败的CALL BACK函数:
     
     

    osip_setcb_ict_transport_error(osip,&application_cb_transport_error);
    osip_setcb_ist_transport_error(osip,&application_cb_transport_error);
    osip_setcb_nict_transport_error(osip,&application_cb_transport_error);
    osip_setcb_nist_transport_error(osip,&application_cb_transport_error);
     

     
     
     
     
     


    注册ICT、NICT、IST、NIST CALL BACK函数

    osip_setcb_ict_2xx_received2(osip,&application_cb_rcvresp_retransmission);
    osip_setcb_ict_3456xx_received2(osip,&application_cb_rcvresp_retransmission);
    osip_setcb_ict_invite_sent2(osip,&application_cb_sndreq_retransmission);
    osip_setcb_ist_2xx_sent2(osip,&application_cb_sndresp_retransmission);
    osip_setcb_ist_3456xx_sent2(osip,&application_cb_sndresp_retransmission);
    osip_setcb_ist_invite_received2(osip,&application_cb_rcvreq_retransmission);
    osip_setcb_nict_2xx_received2(osip,&application_cb_rcvresp_retransmission);
    osip_setcb_nict_3456xx_received2(osip,&application_cb_rcvresp_retransmission);
    osip_setcb_nict_request_sent2(osip,&application_cb_sndreq_retransmission);
    osip_setcb_nist_2xx_sent2(osip,&application_cb_sndresp_retransmission);
    osip_setcb_nist_3456xx_sent2(osip,&application_cb_sndresp_retransmission);
    osip_setcb_nist_request_received2(osip,&application_cb_rcvreq_retransmission);
    osip_setcb_ict_invite_sent (osip,&application_cb_sndinvite);
    osip_setcb_ict_ack_sent     (osip,&application_cb_sndack);
    osip_setcb_nict_register_sent(osip,&application_cb_sndregister);
    osip_setcb_nict_bye_sent     (osip,&application_cb_sndbye);
    osip_setcb_nict_cancel_sent (osip,&application_cb_sndcancel);
    osip_setcb_nict_info_sent    (osip,&application_cb_sndinfo);
    osip_setcb_nict_options_sent (osip,&application_cb_sndoptions);
    osip_setcb_nict_subscribe_sent (osip,&application_cb_sndoptions);
    osip_setcb_nict_notify_sent (osip,&application_cb_sndoptions);
    osip_setcb_nict_unknown_sent(osip,&application_cb_sndunkrequest);
    osip_setcb_ict_1xx_received(osip,&application_cb_rcv1xx);
    osip_setcb_ict_2xx_received(osip,&application_cb_rcv2xx);
    osip_setcb_ict_3xx_received(osip,&application_cb_rcv3xx);
    osip_setcb_ict_4xx_received(osip,&application_cb_rcv4xx);
    osip_setcb_ict_5xx_received(osip,&application_cb_rcv5xx);
    osip_setcb_ict_6xx_received(osip,&application_cb_rcv6xx);
    osip_setcb_ist_1xx_sent(osip,&application_cb_snd1xx);
    osip_setcb_ist_2xx_sent(osip,&application_cb_snd2xx);
    osip_setcb_ist_3xx_sent(osip,&application_cb_snd3xx);
    osip_setcb_ist_4xx_sent(osip,&application_cb_snd4xx);
    osip_setcb_ist_5xx_sent(osip,&application_cb_snd5xx);
    osip_setcb_ist_6xx_sent(osip,&application_cb_snd6xx);
    osip_setcb_nict_1xx_received(osip,&application_cb_rcv1xx);
    osip_setcb_nict_2xx_received(osip,&application_cb_rcv2xx);
    osip_setcb_nict_3xx_received(osip,&application_cb_rcv3xx);
    osip_setcb_nict_4xx_received(osip,&application_cb_rcv4xx);
    osip_setcb_nict_5xx_received(osip,&application_cb_rcv5xx);
    osip_setcb_nict_6xx_received(osip,&application_cb_rcv6xx);
    osip_setcb_nist_1xx_sent(osip,&application_cb_snd1xx);
    osip_setcb_nist_2xx_sent(osip,&application_cb_snd2xx);
    osip_setcb_nist_3xx_sent(osip,&application_cb_snd3xx);
    osip_setcb_nist_4xx_sent(osip,&application_cb_snd4xx);
    osip_setcb_nist_5xx_sent(osip,&application_cb_snd5xx);
    osip_setcb_nist_6xx_sent(osip,&application_cb_snd6xx);
    osip_setcb_ist_invite_received   (osip,&application_cb_rcvinvite);
    osip_setcb_ist_ack_received      (osip,&application_cb_rcvack);
    osip_setcb_ist_ack_received2     (osip,&application_cb_rcvack2);
    osip_setcb_nist_register_received(osip,&application_cb_rcvregister);
    osip_setcb_nist_bye_received     (osip,&application_cb_rcvbye);
    osip_setcb_nist_cancel_received (osip,&application_cb_rcvcancel);
    osip_setcb_nist_info_received    (osip,&application_cb_rcvinfo);
    osip_setcb_nist_options_received (osip,&application_cb_rcvoptions);
    osip_setcb_nist_subscribe_received(osip,&application_cb_rcvoptions);
    osip_setcb_nist_notify_received (osip,&application_cb_rcvoptions);
    osip_setcb_nist_unknown_received (osip,&application_cb_rcvunkrequest);
     

     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     


        在注册完CALL BACK函数后,应用程序可以建立Transaction来调用oSIP的解析器和状态机模块的操作,来实现不同应用程序的需求。
     
     
    6. 参考
           [1] SIP   --        RFC3261      (http://www.ietf.org)
           [2] SDP --    RFC2327(http://www.ieft.org)
           [3] oSIP Library          --    http://www.gnu.org/software/osip/
           [4] oSIP mailing list      --    http://www.atosc.org/pipermail/public/osip/
  • 相关阅读:
    「Wallace 笔记」K-D tree 区域查询时间复杂度简易证明
    「LOJ #2980」「THUSCH 2017」大魔法师
    「Wallace 笔记」快速上手回文自动机(PAM)
    「ZJU Summer Training 2020
    「AtCoder AGC002F」Leftmost Ball
    文案高手的18项修炼
    高性能MySQL实战
    300分钟搞懂 Spring Cloud
    腾讯产品启示录
    300分钟吃透分布式缓存
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13318523.html
Copyright © 2011-2022 走看看