JAIN SIP在Android抱怨核心类的错误餐巾使用错误的是问题,怎么解决

基于JAINSIP协议栈的一个简单SIP服务器实现流程
SIP服务器采用B2BUA,sip呼叫控制实现流程
SIP服务器采用B2BUA,sip呼叫控制实现流程:&
INVITE的请求:&
收到INVITE后,克隆INVITE消息。替换Request&URI被叫注册的地址。&
替换VIA头为服务器地址。通过该INVITE请求得到客户端事务并通过&
该事务来发送INVITE请求。&
180,200&OK响应的处理:&
根据返回的响应码创建新的响应。&
替换CONTACT头地址为服务器的地址。&
拷贝原响应中的媒体内容至新的响应中。&
通过INVITE中保存下来的服务端事务发送响应消息。&
ACK的处理:&
从ACK请求中得到序列数。&
通过被叫对话来创建新的ACK请求。&
通过被叫对话发送ACK请求。&
BYE的处理流程:&
根据被叫端的客户端事务得到发送给被叫的INVITE请求,根据INVITE请求创建BYE消息。&
BYE响应消息处理流程:&
根据DIALOG得到服务端事务,并由此得到BYE请求。根据BYE请求创建响应。&
CANCEL的处理流程:&
向主叫响应CANCEL&200&OK。&
根据客户端事务得到发送给主叫的INVITE请求中的URI,CALLID,FROM,TO,VIA头域来创建CANCEL请求。&
注:非200&OK的ACK响应是由协议栈来实现的,不需要应用层来发送。也就是说,ACK消息不会经过应用层。&
package com.voip.
import gov.nist.javax.sip.address.SipU
import gov.nist.javax.sip.header.CS
import gov.nist.javax.sip.header.C
import gov.nist.javax.sip.header.ContentL
import gov.nist.javax.sip.header.ContentT
import gov.nist.javax.sip.header.F
import gov.nist.javax.sip.header.V
import java.text.ParseE
import java.util.ArrayL
import java.util.H
import java.util.L
import java.util.P
import java.util.T
import javax.sip.*;
import javax.sip.address.A
import javax.sip.address.AddressF
import javax.sip.address.URI;
import javax.sip.header.CallIdH
import javax.sip.header.ContactH
import javax.sip.header.ExpiresH
import javax.sip.header.FromH
import javax.sip.header.H
import javax.sip.header.HeaderF
import javax.sip.header.MaxForwardsH
import javax.sip.header.RecordRouteH
import javax.sip.header.ToH
import javax.sip.header.ViaH
import javax.sip.message.MessageF
import javax.sip.message.R
import javax.sip.message.R
public class SipPhone implements SipListener
public void processDialogTerminated(DialogTerminatedEvent arg0) {
// TODO Auto-generated method stub
System.out.println(&processDialogTerminated & + arg0.toString());
public void processIOException(IOExceptionEvent arg0) {
// TODO Auto-generated method stub
System.out.println(&processIOException & + arg0.toString());
* 保存当前注册的用户
private static Hashtable&URI, URI& currUser = new Hashtable();
* @author software
* 注册定时器
class TimerTask extends Timer
* default constructor
public TimerTask()
如果定时任务到,则删除该用户的注册信息
public void run()
* 服务器侦听IP地址
private String ipAddr = &192.168.0.20&;
* 服务器侦听端口
private int port = 5060;
* 处理register请求
* @param request 请求消息
private void processRegister(Request request, RequestEvent requestEvent)
if (null == request)
System.out.println(&processInvite request is null.&);
//System.out.println(&Request & + request.toString());
ServerTransaction serverTransactionId = requestEvent.getServerTransaction();
Response response =
ToHeader head = (ToHeader)request.getHeader(ToHeader.NAME);
Address toAddress = head.getAddress();
URI toURI = toAddress.getURI();
ContactHeader contactHeader = (ContactHeader) request.getHeader(&Contact&);
Address contactAddr = contactHeader.getAddress();
URI contactURI = contactAddr.getURI();
System.out.println(&processRegister from: & + toURI + & request str: & + contactURI);
int expires = request.getExpires().getExpires();
// 如果expires不等于0,则为注册,否则为注销。
if (expires != 0 || contactHeader.getExpires() != 0)
currUser.put(toURI, contactURI);
System.out.println(&register user & + toURI);
currUser.remove(toURI);
System.out.println(&unregister user & + toURI);
response = msgFactory.createResponse(200, request);
System.out.println(&send register response
: & + response.toString());
if(serverTransactionId == null)
serverTransactionId = sipProvider.getNewServerTransaction(request);
serverTransactionId.sendResponse(response);
//serverTransactionId.terminate();
System.out.println(&register serverTransaction: & + serverTransactionId);
System.out.println(&processRequest serverTransactionId is null.&);
catch (ParseException e)
// TODO Auto-generated catch block
e.printStackTrace();
catch (SipException e)
// TODO Auto-generated catch block
e.printStackTrace();
catch (InvalidArgumentException e)
// TODO Auto-generated catch block
e.printStackTrace();
* 处理invite请求
* @param request 请求消息
private void processInvite(Request request, RequestEvent requestEvent)
if (null == request)
System.out.println(&processInvite request is null.&);
// 发送100 Trying
serverTransactionId = requestEvent.getServerTransaction();
if (serverTransactionId == null)
serverTransactionId = sipProvider.getNewServerTransaction(request);
callerDialog = serverTransactionId.getDialog();
Response response = msgFactory.createResponse(Response.TRYING, request);
serverTransactionId.sendResponse(response);
//查询目标地址
URI reqUri = request.getRequestURI();
URI contactURI = currUser.get(reqUri);
System.out.println(&processInvite rqStr=& + reqUri + & contact=& + contactURI);
//根据Request uri来路由,后续的响应消息通过VIA来路由
Request cliReq = msgFactory.createRequest(request.toString());
cliReq.setRequestURI(contactURI);
Via callerVia = (Via)request.getHeader(Via.NAME);
Via via = (Via) headerFactory.createViaHeader(ipAddr, port, &UDP&, callerVia.getBranch()+&sipphone&);
// FIXME 需要测试是否能够通过设置VIA头域来修改VIA头域值
cliReq.removeHeader(Via.NAME);
cliReq.addHeader(via);
// 更新contact的地址
ContactHeader contactHeader = headerFactory.createContactHeader();
Address address = addressFactory.createAddress(&sip:sipsoft@& + ipAddr +&:&+ port);
contactHeader.setAddress(address);
contactHeader.setExpires(3600);
cliReq.setHeader(contactHeader);
clientTransactionId = sipProvider.getNewClientTransaction(cliReq);
clientTransactionId.sendRequest();
System.out.println(&processInvite clientTransactionId=& + clientTransactionId.toString());
System.out.println(&send invite to callee: & + cliReq);
catch (TransactionUnavailableException e1)
// TODO Auto-generated catch block
e1.printStackTrace();
catch (SipException e)
// TODO Auto-generated catch block
e.printStackTrace();
catch (ParseException e)
e.printStackTrace();
catch (Exception e)
e.printStackTrace();
* 处理SUBSCRIBE请求
* @param request 请求消息
private void processSubscribe(Request request)
if (null == request)
System.out.println(&processSubscribe request is null.&);
ServerTransaction serverTransactionId =
serverTransactionId = sipProvider.getNewServerTransaction(request);
catch (TransactionAlreadyExistsException e1)
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (TransactionUnavailableException e1)
// TODO Auto-generated catch block
e1.printStackTrace();
Response response =
response = msgFactory.createResponse(200, request);
if (response != null)
ExpiresHeader expireHeader = headerFactory.createExpiresHeader(30);
response.setExpires(expireHeader);
System.out.println(&response : & + response.toString());
if(serverTransactionId != null)
serverTransactionId.sendResponse(response);
serverTransactionId.terminate();
System.out.println(&processRequest serverTransactionId is null.&);
catch (ParseException e)
// TODO Auto-generated catch block
e.printStackTrace();
catch (SipException e)
// TODO Auto-generated catch block
e.printStackTrace();
catch (InvalidArgumentException e)
// TODO Auto-generated catch block
e.printStackTrace();
* 处理BYE请求
* @param request 请求消息
private void processBye(Request request, RequestEvent requestEvent)
if (null == request || null == requestEvent)
System.out.println(&processBye request is null.&);
Request byeReq =
Dialog dialog = requestEvent.getDialog();
System.out.println(&calleeDialog : & + calleeDialog);
System.out.println(&callerDialog : & + callerDialog);
if (dialog.equals(calleeDialog))
byeReq = callerDialog.createRequest(request.getMethod());
ClientTransaction clientTran = sipProvider.getNewClientTransaction(byeReq);
callerDialog.sendRequest(clientTran);
calleeDialog.setApplicationData(requestEvent.getServerTransaction());
else if (dialog.equals(callerDialog))
byeReq = calleeDialog.createRequest(request.getMethod());
ClientTransaction clientTran = sipProvider.getNewClientTransaction(byeReq);
calleeDialog.sendRequest(clientTran);
callerDialog.setApplicationData(requestEvent.getServerTransaction());
System.out.println(&&);
System.out.println(&send bye to peer:& + byeReq.toString());
catch (SipException e)
// TODO Auto-generated catch block
e.printStackTrace();
* 处理CANCEL请求
* @param request 请求消息
private void processCancel(Request request)
if (null == request)
System.out.println(&processCancel request is null.&);
* 处理INFO请求
* @param request 请求消息
private void processInfo(Request request)
if (null == request)
System.out.println(&processInfo request is null.&);
* 处理ACK请求
* @param request 请求消息
private void processAck(Request request, RequestEvent requestEvent)
if (null == request)
System.out.println(&processAck request is null.&);
Request ackRequest =
CSeq csReq = (CSeq)request.getHeader(CSeq.NAME);
ackRequest = calleeDialog.createAck(csReq.getSeqNumber());
calleeDialog.sendAck(ackRequest);
System.out.println(&send ack to callee:& + ackRequest.toString());
catch (SipException e)
// TODO Auto-generated catch block
e.printStackTrace();
catch (InvalidArgumentException e)
// TODO Auto-generated catch block
e.printStackTrace();
* 处理CANCEL消息
* @param request
* @param requestEvent
private void processCancel(Request request, RequestEvent requestEvent)
// 判断参数是否有效
if (request == null || requestEvent == null)
System.out.println(&processCancel input parameter invalid.&);
// 发送CANCEL 200 OK消息
Response response = msgFactory.createResponse(Response.OK, request);
ServerTransaction cancelServTran = requestEvent.getServerTransaction();
if (cancelServTran == null)
cancelServTran = sipProvider.getNewServerTransaction(request);
cancelServTran.sendResponse(response);
// 向对端发送CANCEL消息
Request cancelReq =
Request inviteReq = clientTransactionId.getRequest();
List list = new ArrayList();
Via viaHeader = (Via)inviteReq.getHeader(Via.NAME);
list.add(viaHeader);
CSeq cseq = (CSeq)inviteReq.getHeader(CSeq.NAME);
CSeq cancelCSeq = (CSeq)headerFactory.createCSeqHeader(cseq.getSeqNumber(), Request.CANCEL);
cancelReq = msgFactory.createRequest(inviteReq.getRequestURI(),
inviteReq.getMethod(),
(CallIdHeader)inviteReq.getHeader(CallIdHeader.NAME),
cancelCSeq,
(FromHeader)inviteReq.getHeader(From.NAME),
(ToHeader)inviteReq.getHeader(ToHeader.NAME),
(MaxForwardsHeader)inviteReq.getHeader(MaxForwardsHeader.NAME));
ClientTransaction cancelClientTran = sipProvider.getNewClientTransaction(cancelReq);
cancelClientTran.sendRequest();
catch (ParseException e)
// TODO Auto-generated catch block
e.printStackTrace();
catch (TransactionAlreadyExistsException e)
// TODO Auto-generated catch block
e.printStackTrace();
catch (TransactionUnavailableException e)
// TODO Auto-generated catch block
e.printStackTrace();
catch (SipException e)
// TODO Auto-generated catch block
e.printStackTrace();
catch (InvalidArgumentException e)
// TODO Auto-generated catch block
e.printStackTrace();
private ServerTransaction serverTransactionId =
/* (non-Javadoc)
* @see javax.sip.SipListener#processRequest(javax.sip.RequestEvent)
public void processRequest(RequestEvent arg0)
Request request = arg0.getRequest();
if (null == request)
System.out.println(&processRequest request is null.&);
System.out.println(&processRequest:& + request.toString());
if (Request.INVITE.equals(request.getMethod()))
processInvite(request, arg0);
else if (Request.REGISTER.equals(request.getMethod()))
processRegister(request, arg0);
else if (Request.SUBSCRIBE.equals(request.getMethod()))
processSubscribe(request);
else if (Request.ACK.equalsIgnoreCase(request.getMethod()))
processAck(request, arg0);
else if (Request.BYE.equalsIgnoreCase(request.getMethod()))
processBye(request, arg0);
else if (Request.CANCEL.equalsIgnoreCase(request.getMethod()))
processCancel(request, arg0);
System.out.println(&no support the method!&);
* 主叫对话
private Dialog calleeDialog =
* 被叫对话
private Dialog callerDialog =
ClientTransaction clientTransactionId =
* 处理BYE响应消息
* @param reponseEvent
private void doByeResponse(Response response, ResponseEvent responseEvent)
Dialog dialog = responseEvent.getDialog();
Response byeResp =
if (callerDialog.equals(dialog))
ServerTransaction servTran = (ServerTransaction)calleeDialog.getApplicationData();
byeResp = msgFactory.createResponse(response.getStatusCode(), servTran.getRequest());
servTran.sendResponse(byeResp);
else if (calleeDialog.equals(dialog))
ServerTransaction servTran = (ServerTransaction)callerDialog.getApplicationData();
byeResp = msgFactory.createResponse(response.getStatusCode(), servTran.getRequest());
servTran.sendResponse(byeResp);
System.out.println(&send bye response to peer:& + byeResp.toString());
catch (ParseException e)
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SipException e)
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvalidArgumentException e)
// TODO Auto-generated catch block
e.printStackTrace();
/* (non-Javadoc)
* @see javax.sip.SipListener#processResponse(javax.sip.ResponseEvent)
public void processResponse(ResponseEvent arg0)
// FIXME 需要判断各个响应对应的是什么请求
Response response = arg0.getResponse();
System.out.println(&recv the response :& +
response.toString());
System.out.println(&respone to request : & + arg0.getClientTransaction().getRequest());
if (response.getStatusCode() == Response.TRYING)
System.out.println(&The response is 100 response.&);
ClientTransaction clientTran = (ClientTransaction) arg0.getClientTransaction();
if (Request.INVITE.equalsIgnoreCase(clientTran.getRequest().getMethod()))
int statusCode = response.getStatusCode();
Response callerResp =
callerResp = msgFactory.createResponse(statusCode, serverTransactionId.getRequest());
// 更新contact头域值,因为后面的消息是根据该URI来路由的
ContactHeader contactHeader = headerFactory.createContactHeader();
Address address = addressFactory.createAddress(&sip:sipsoft@&+ipAddr+&:&+port);
contactHeader.setAddress(address);
contactHeader.setExpires(3600);
callerResp.addHeader(contactHeader);
// 拷贝to头域
ToHeader toHeader = (ToHeader)response.getHeader(ToHeader.NAME);
callerResp.setHeader(toHeader);
// 拷贝相应的消息体
ContentLength contentLen = (ContentLength)response.getContentLength();
if (contentLen != null && contentLen.getContentLength() != 0)
ContentType contentType = (ContentType)response.getHeader(ContentType.NAME);
System.out.println(&the sdp contenttype is & + contentType);
callerResp.setContentLength(contentLen);
//callerResp.addHeader(contentType);
callerResp.setContent(response.getContent(), contentType);
System.out.println(&sdp is null.&);
if (serverTransactionId != null)
callerDialog = serverTransactionId.getDialog();
calleeDialog = clientTran.getDialog();
serverTransactionId.sendResponse(callerResp);
System.out.println(&callerDialog=& + callerDialog);
System.out.println(&serverTransactionId.branch=& + serverTransactionId.getBranchId());
System.out.println(&serverTransactionId is null.&);
System.out.println(&send response to caller : & + callerResp.toString());
else if (Request.BYE.equalsIgnoreCase(clientTran.getRequest().getMethod()))
doByeResponse(response, arg0);
else if (Request.CANCEL.equalsIgnoreCase(clientTran.getRequest().getMethod()))
//doCancelResponse(response, arg0);
catch (ParseException e)
// TODO Auto-generated catch block
e.printStackTrace();
catch (SipException e)
// TODO Auto-generated catch block
e.printStackTrace();
catch (InvalidArgumentException e)
// TODO Auto-generated catch block
e.printStackTrace();
catch (Exception ex)
ex.printStackTrace();
private void doCancelResponse(Response response, ResponseEvent responseEvent)
需要验证参数的有效性
ServerTransaction servTran = (ServerTransaction)callerDialog.getApplicationData();
Response cancelR
cancelResp = msgFactory.createResponse(response.getStatusCode(), servTran.getRequest());
servTran.sendResponse(cancelResp);
catch (ParseException e)
// TODO Auto-generated catch block
e.printStackTrace();
catch (SipException e)
// TODO Auto-generated catch block
e.printStackTrace();
catch (InvalidArgumentException e)
// TODO Auto-generated catch block
e.printStackTrace();
public void processTimeout(TimeoutEvent arg0)
// TODO Auto-generated method stub
System.out.println(& processTimeout & + arg0.toString());
public void processTransactionTerminated(TransactionTerminatedEvent arg0) {
// TODO Auto-generated method stub
System.out.println(& processTransactionTerminated & + arg0.getClientTransaction().getBranchId()
+ & & + arg0.getServerTransaction().getBranchId());
private static SipStack sipStack =
private static AddressFactory addressFactory =
private static MessageFactory msgFactory =
private static HeaderFactory headerFactory =
private static SipProvider sipProvider =
private void init()
SipFactory sipFactory =
sipFactory = SipFactory.getInstance();
if (null == sipFactory)
System.out.println(&init sipFactory is null.&);
sipFactory.setPathName(&gov.nist&);
Properties properties = new Properties();
properties.setProperty(&javax.sip.STACK_NAME&, &sipphone&);
// You need 16 for logging traces. 32 for debug + traces.
// Your code will limp at 32 but it is best for debugging.
properties.setProperty(&gov.nist.javax.sip.TRACE_LEVEL&, &32&);
properties.setProperty(&gov.nist.javax.sip.DEBUG_LOG&,
&sipphonedebug.txt&);
properties.setProperty(&gov.nist.javax.sip.SERVER_LOG&,
&sipphonelog.txt&);
sipStack = sipFactory.createSipStack(properties);
catch (PeerUnavailableException e)
// TODO Auto-generated catch block
e.printStackTrace();
headerFactory = sipFactory.createHeaderFactory();
addressFactory = sipFactory.createAddressFactory();
msgFactory = sipFactory.createMessageFactory();
ListeningPoint lp = sipStack.createListeningPoint(&192.168.0.20&,
5060, &udp&);
SipPhone listener =
sipProvider = sipStack.createSipProvider(lp);
System.out.println(&udp provider & + sipProvider.toString());
sipProvider.addSipListener(listener);
catch (Exception ex)
ex.printStackTrace();
* 程序入口
* @param args
public static void main(String []args)
new SipPhone().init();
本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 []
本文出处:网络 作者:匿名
------分隔线----------------------------
将本文分享到微信
使用该AEC算法要注意两点:1)延时要小,因为算法默认滤波器长...
访问http://192.168.11.75:8080/player.html,可以播放。用三星P7500安卓平...
我一直认为,工程师,尤其 是一线的,是最接近真相的人,也是...
今天尝试编写了一个基于 v4l2 的摄像头应用, 目前仅仅实现从摄...
onvif规范的实现:成功实现ONVIF协议RTSP-Video-Stream与OnvifDeviceMana...
onvif规范的实现:server端Discovery实现,通过OnvifTestTool12.06测试:网...使用JAIN&SIP开发基于SIP协议的应用
SIP开发基于SIP协议的应用摘要:会话发起协议(SIP)将在3G网络中发挥重要的作用,而JAIN
SIP是用Java语言实现的SIP类库。简要介绍了SIP协议的规范,详细分析了JAIN
SIP的体系结构和实现机制,并用代码片断和交互图的方式描述了基于SIP协议应用的开发过程。用JAIN
sIP 开发基于SIP
协议的应用不仅可以提高开发效率,而且将使应用程序获得较高的可靠性和较好的移植性。
SIP(Session Initiation
Protocol,会话发起协议)是由IETF(Internet工程任务组)提出的IP信令协议。它的主要作用是解决IP网中的信令控制,以及同SoftSwitch的通信,从而构成下一代网络的增值业务平台,为通信、交通、金融等行业提供更好的增值业务。
1.1 SIP概述
SIP是一个与HTTP和SMTP类似的、基于文本的应用层控制信令协议,用于建立、修改或结束一个或多个参与者的会话。SIP会话中的各参与方可以通过多播或单播的方式进行通信。SIP通过代理和重定向请求到用户当前位置来支持用户的移动性。由于SIP没有捆绑于任何特定的会议控制协议,因而协议具有普遍性,可以用于开发Internet多媒体会议、Internet电话呼叫、多媒体分发、网络游戏以及虚拟现实等方面的应用。SIP对传输层和网络层没有特殊要求,除IP网络之外,还可以运行于ATM
AAL5,IPX,Frame
Relay或x.25上。而在IP网络中,SIP可以利用UDP或TCP作为传输层协议,一般情况下使用UDP,而传输的可靠性则由SIP来保证。与HTrP类似,SIP定义了6种基本的方法、6类状态编码和一系列的SIP消息首部用于信令的传递和控制功能的完成。SIP的方法定义不同的信令处理功能,6种方法包括INVITE。BYE,CANCEL,分别用于呼叫的请求、挂断和取消;ACK用于对请求回应的确认;OPTIONS用于会话中参数的协商和改变;REGISTER用于用户的位置信息在SIP服务器上登记。状态编码从lxx到6xx,在请求回应中指出服务器端对请求处理的结果和工作状态,如lxx指出请求在进一步处理中,需要暂时等待,2xx表示请求处理成功结束,3xx表示请求被重定向,等等。消息首部用来指明一些有关主叫/被叫、消息路径、报文体的信息,如Call—ID用于唯一标识一次会话呼叫;CSeq唯一标识一次会话中的一个请求;To指出请求的接收方;From指出请求的发起方;Contact可以包含位置信息,用于实现一些高级功能,如呼叫转移等。
1.2 SIP的主要运行过程
SIP的主要运行过程包括:注册、通过代理模式建立连接、通过重定向模式建立连接和呼叫复制。注册过程包括以下步骤:用户端启动后,通过组播包向注册服务器发送注册请求;由注册服务器决定注册超期时限;注册服务器向定向服务器发送当前的注册表;注册服务器支持代理服务以保障用户的移动性。通过代理模式建立连接包括以下步骤:代理服务器首先接收用户端发送的INVITE消息包;代理服务器通过定位服务器来确定被叫方的位置;代理服务器将INVITE消息包发送给被叫方;被叫方的应用程序响应呼叫并向代理服务器发送成功消息包,该消息包通过相同的路由发送给代理服务器;代理服务器向呼叫发起方转发呼叫成功消息;呼叫发起方接收到成功建立连接的消息,并直接向被叫方发送ACK消息包,不再通过代理服务器。通过重定向服务器建立连接时,重定向服务器并不对请求消息包做任何处理,直接将代理服务器的地址发送给呼叫发起方。呼叫复制是代理服务器将呼叫发起方的请求复制后发送给被叫方的多个终端,并选择最早应答的终端与其建立连接。一旦呼叫方和被呼叫方建立起连接,则它们之间的交互将直接进行而不需要任何第三方参与;任何一方都可以直接向对方发送BYE
消息终止会话。
SIP和H'ITP以及SMTP一样,SIP使用ASCII来定义,任何一个开发人员可以很容易地使用任何程序设计语言来实现这个协议,他们所要处理的都将是字符串数据。目前已经有多个SIP的实现。JAIN(Java
AdvancedIntcnigcnt
Network)是SUN公司开发的一系列高级智能网Java类库,其中JAIN
SIP是其对SIP提供支持的类库。由于JAIN SIP API是对SIP标准
的完整定义,所以任何基于SIP的应用都可将JAIN SIP
API作为Java标准接口,用到任何SIP应用实例中。这意味着应用服务器、SIP
电话、网关及网关控制器、SIP服务器、基于SIP的业务、SIP计费解决方案、开发工具包、SIP测试工具、SIP用户代理以及SIP网络管理,均可利用JAIN
SIP API来提供一个高度可移植性的实现。
2.1 JAIN SIP体系结构
SIP利用Java的面向对象特性,用对象、消息以及事件来描述SIP协议。在JAIN
SIP体系结构中,为所有SIP报头和报文定义了类,并借助提供者/监听者(SipProvidcr!SipListcncr)接口,将用于处理报文的JavaBcans体系结构的接口定义为事件。一个典型的JAIN
SIP应用程序如图1所示。应用程序 应用程序
图1 JAIN SIP应用程序结构
Stack直接对应于实现SIP协议栈的数据结构,所有的SIP消息和状态码都由Stack通过网络收发。它不提供面向对象功能,可以说是SIP
的一个原始实现。SipProvider是一个接口,通过Listening
Point封装了对Stack进行操作的方法,将SIP
以面向对象的形式提供给上层对象。SipProvider不关心一个SIP消息在应用程序中的意义,它的职责仅仅是通过上、下层的接口处理SIP消息的准确发送和接收。在逻辑上,两个SIP应用程序之间的交互就表现为它们之间的SipProvidcr进行交互。SIP协议本质上是一个请求/应答协议,是一个无状态的协议,这样的目的是为了简化各代理服务器的功能,提高其处理用户请求的能力,同时也增强了SIP应用程序的灵活性;但另一方面,无状态的协议又不能很好地直接支持事务的概念。为了给上层应用提供一个易用的事务支持,SipProvider提供了客户端事务(Client
Transaction)和服务器端事务(Server
Transaction)的创建方法,它提供了对有状态的请求/应答消息的良好支持。SipProvider同时支持无状态的请求/应答消息,这是SIP的默认消息类型。一个应用程序中可以有多个SipProvidcr,每个对应一个Stack。应用程序通过一个SipListener管理一个或多个SipProvider。SipProvider的行为依赖于应用程序的业务逻辑。当一个SipProvider建立之后,将被注册到一个SipListener;应用程序如果需要访问某个SipProvider,就通过SipListcncr向该SipProvider发送消息;如果SipProvidcr收到了其他SipProvidcr的sIP消息,需要将其传递给应用程序进行解析,此时它将产牛一个事件,sipListencr理解事件的含义并能根据不同的事件触发相应的响应。
2.2 JAIN SIP 对象初始化过程从JAIN
SIP应用程序的结构我们可以看出,JAIN
SIP的开发都是围绕着SipListener和SipProvidcr进行的。实际上,还有其他对象参与共同实现其功能,在程序的开始阶段必须进行初始化,以创建一系列必须的对象。图2描述了一个JAIN
SIP应用程序中各个对象的创建关系。图2 JAIN
SIP对象体系结构对象的创建过程为:
SIP应用程序调用ctcatcListener方法创建出一个全局唯一的SipListener对象:
2)SipListener通过getlnstance方法创建SipFactory对象,并通过其创建SipStack对象;
3)SipStack对象创建SipProvidcr,并将其私有的SIP
Stack交由SipProvider管理;
4)一旦一个SipProvidcr成功建立,SipListcncr就对其进行注册,建立起消息/事件机制,从而完成初始化。SipStack对象负责维护SIP
Stack,因而创建的时候有一
些重要的属性需要设置,其代码片断如下:
Properties properties =new Properties();
Properties.setProperty(”jav~x.sip.IP_ADDRESS”,
”211.69.194.123”);
Properties.setProperty(”java.sip.OUTBOUND—PROXY“,
”202.1 14.0.243:5070/UDP“);
. . . // other initialization prope rties
sipStack=sipFactory.createSipStack(properties);
SIP呼叫请求的发送与处理当各对象初始化完成之后就可以通过请求和响应消息的方式和其他的JAIN
SIP对象进行通信了,JAIN
SIP提供给程序员完全面向对象的方式来处理这种请求和响应。以下用几个代码片断来说明。
1)创建请求消息,将SIP
Request消息以正确的参数填充,包括请求类型、请求编号等:
SipURI rcquestURI =
addressFactory.createSipURI(toUser,toSipAddress);
,,create other headersRequest request =
messagcFactory.createRequest
(requestURI,Request.INVITE,eaUldHeader,eSeqHeader,fromHeader,toHeader,viaHeaders,maxForwards);
2)SipProvider创建ClicntTransaction对象,将刚刚填充的request发送出去:
ClientTransaction inviteTid
=SipProvider.getNewClientTransaction(request);InviteTid.sendRequest();
3)将收到的SIP Request作为事件,交由ServcrTransaction
处理:public void processRequest(RequestEvent requestEvent)lRequest
request=requestEvent.getRequest();ServerTmnsaction
st=requestEvent.getServerTransaction();
//do request specific processing here
3 JAIN SIP开发的一个实例使用JAIN
SIP既可以开发用户代理端实例(包括UAC
UAS),也可以方便地开发各种SIP服务器,本节以一个无状态的SIP代理服务器为例说明。该服务器维护一个本地用户的列表,为本地用户转发呼叫,并记录其当前位置。当服务器收到一个对本地用户的呼叫时,它将查询数据库得到呼叫目标的当前位置,并将呼叫转发到相应位置。对于外来漫游到本地的用户,该服务器将把对其的呼叫转发到其归属服务器。图3解释了无状态SIP服务器接收本地用户的注册并转发呼叫的过程。
图4 无状态SIP代理服务器注册过程使用JAIN
SIP对象和方法,可以很容易地对上述过程提供支持,我们仅以注册(Register)过程为例。图4是JAIN
SIP开发的无状态SIP服务器接收用户的注册过程交互图。
代理服务器处理用户代理的注册过程为:
1)SipStack接收到用户代理发送的REGISTER请求;
2)SipProvider获取SipStack中的请求消息字符串,并交由SipParser格式化为标准请求消息;
3)SipProvider向SipListener通报用户注册事件;
4)SipListener被事件触发,在用户数据库中校验用户的权限,确认后如需更新则更新数据库;
5)验证成功后SipListener返回状态码给SipProvider,SipProvider将其转发给SipStack,最后发回给用户代理。
本文所述的SIP代理服务器注册过程的实例是一个较有代表性的例子,如果采用直接解析SIP消息的方法将使开发过程纠缠于大量的文本解析与处理上,使用JAIN
SIP则将其转化为对消息和事件的处理,提高了开发的效率。由于Java语言提供的垃圾收集以及平台无关特性,使用JAIN
SIP同时也使应用程序获得较高的可靠性和移植性。
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。}

我要回帖

更多关于 一使用光域网错误 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信