Java web服务器实现SIP通讯(或GB28181),一般有两种选择:SipServlet和JainSip
前者更适合服务器,后者较适合客户端
前者用类似web servlet的方式实现了sip通信,直接就实现了多线程的sip通信的并发
后者相对底层一点,不具有并发能力
但,前者需要Web容器的支持,目前好象能用的只有两三种,且与web servlet并存性好像也不好
故,考虑到要用tomcat容器,所以用JainSip实现具有sip通信能力的web服务器
1. 设计思路
JainSip实现,主要是面向SipListener监听接口编程
此监听接口一个项目中只能有一个实现,但可以同时对多个端口进行监听
一个监听端口对应一个ListeningPoint监听对象,并由一个SipProvider对象管理
此接口要实现6个处理方法:
public void processRequest(RequestEvent evt)
public void processResponse(ResponseEvent evt)
public void processTimeout(TimeoutEvent evt)
public void processTransactionTerminated(TransactionTerminatedEvent evt)
public void processDialogTerminated(DialogTerminatedEvent evt)
public void processIOException(IOExceptionEvent evt)
这些方法是串行处理的,要用多线程实现并行处理
前两个是接收消息,发送sip消息要用对应端口的SipProvider对象来发送
2. 监听的建立
建立实现SipListener接口的基类:
public abstract class Siplistener implements SipListener
构造函数中设置sip工厂类参数:
sipFactory = SipFactory.getInstance();
sipFactory.setPathName("gov.nist");
用一个方法创建监听:
public void createListenPoint(String listenerName, String serverName, String ip, int port)
//创建SipStack
Properties properties = new Properties();
properties.setProperty("javax.sip.STACK_NAME", serverName);
properties.setProperty("javax.sip.IP_ADDRESS", ip);
properties.setProperty("gov.nist.javax.sip.TRACE_LEVEL", 32);
properties.setProperty("gov.nist.javax.sip.SERVER_LOG", "textclient.txt");
properties.setProperty("gov.nist.javax.sip.DEBUG_LOG", "textclientdebug.log");
SipStack sipStack = sipFactory.createSipStack(proerties);
//udp 创建SipProvider
SipProvider sipProvider;
ListeningPoint udp = sipStack.createListeningPoint(ip, port, "udp");
sipProvider = sipStack.createSipProvider(udp);
//保存SipProvider对象
String strHashcode = Integer.toHexString(sipProvider.hashCode());
sipProviderMap.put(strHashcode, sipProvider);
sipProviderNameMap.put(listenerName+"/udp", strHashcode);
sipProviderNameMap.put(strHashcode, listenerName+"/udp");
sipProvider.addSipListener(this);
//tcp 创建SipProvider
ListeningPoint tcp = sipStack.createListeningPoint(ip, port, "tcp");
sipProvider = sipStack.createSipProvider(tcp);
//保存SipProvider对象
String strHashcode = Integer.toHexString(sipProvider.hashCode());
sipProviderMap.put(strHashcode, sipProvider);
sipProviderNameMap.put(listenerName+"/tcp", strHashcode);
sipProviderNameMap.put(strHashcode, listenerName+"/tcp");
sipProvider.addSipListener(this);
可以建立多个端口的tcp/udp监听,需根据监听名和传输类型方便取出各自的SipProvider
3. 处理线程
建立请求处理线程:
public abstract class SipProcessReqThread implements Runnable {
protected Siplistener siplistener;
protected Request req;
protected RequestEvent evt;
protected SipProvider sipProvider;
protected String listenerName;
public void run() {
if(null!=req){
onProcess();
}
}
protected abstract void onProcess();
public void setParam(Siplistener siplistener, Request req, RequestEvent evt, SipProvider sipProvider, String listenerName) {
this.siplistener=siplistener;
this.req=req;
this.evt=evt;
this.sipProvider=sipProvider;
this.listenerName=listenerName;
}
}
超时处理线程:
public abstract class SipDialogTimeout implements Runnable {
protected TimeoutEvent evt;
protected Dialog dialog;
protected boolean isReturn;
public void run() {
if(evt.isServerTransaction()){
ServerTransation serverTransation = evt.getServerTransation();
if(serverTransation!=null){
dialog=serverTransation.getDialog();
}
isReturn = true;
}else{
ClientTransation clientTransation = evt.getClientTransation();
if(clientTransation!=null){
dialog=clientTransation.getDialog();
}
isReturn = true;
}
if(null!=dialog){
onProcess(isReturn);
}
}
protected abstract void onProcess(boolean isReturn);
public void setParam(TimeoutEvent evt) {
this.evt=evt;
}
}
其它处理线程与上面的类似
4. 处理方法
接收请求的处理:
public void processRequest(RequestEvent evt) {
Request req = evt.getRequest();
String str=evt.getSource().toString();
str=str.substring(str.indexOf('@')+1);
SipProvider sipProvider=sipProviderMap.get(str);
String strHashcode=Integer.toHexString(sipProvider.hashCode());
String strListenerName=sipListenerNameMap.get(strHashcode);
SipProcessReqThread sipProcessReqThread=new_SipProcessReqThread();
sipProcessReqThread.setParam(this, req, evt, sipProvider, strListenerName);
startThread(sipProcessReqThread);
}
超时处理:
public void processTimeout(TimeoutEvent evt) {
SipDialogTimeout sipDialogTimeout=new_SipDialogTimeout();
sipDialogTimeout.setParam(evt);
startThread(sipDialogTimeout);
}
其它处理与之类似
启动Runnable线程的共用方法:
private void startThread(Runnable runnable) {
Thread thread=new Thread(runnable);
try{
thread.start();
}catch(Exception e){
}
}
5. 发送请求
public boolean sendRequest(String name, String type, Request req) {
SipProvider sipProvider=getProvider(name,type);
if(sipProvider==null){
return false;
}
try{
sipProvider.sendRequest(req);
}catch(SipException e){
return false;
}
return true;
}
6. 处理对象的注入
用方法
public abstract SipDialogTimeout new_SipDialogTimeout();
public abstract SipProcessReqThread new_ProcessReqThread();
public abstract SipProcessRespThread new_ProcessRespThread();
子类实现后,注入新对象
7. Jar包
concurrent.jar
JainSipApi1.2.jar
JainSipRi1.2.jar
log4j-1.2.8.jar