Eclipse Mobicents
唐弘和
2023-12-01
Mobicents Eclipse:
http://mobicents.googlecode.com/svn/downloads/sip-servlets-eclipse-update-site
什么是SIP Servlets?
SIP Servlet 是一个 基于Java 语言的 server-side 组件,就类似于Java Servlet 一样,只不过SIP Servlet 需要运行在 SIP Servlet 容器中。
而且SIP Servlet主要用来处理SIP请求,而Servlet用来处理HTTP请求。
HTTP Servlet 与 SIP Servlet的不同之处:
1. HTTP Servlet 都会有一个context对象,也就是每个Servlet都有一个上下文的概念。而SIP Servlet没有。
2. HTTP Servlet 通常会返回一个HTML 页面或者某种形式的字符串(比如JSON),而SIP请求通常只是起到连接服务器与客户端的作用。
3. SIP 是一个P2P的协议,所以服务器端同样可以向客户端发送SIP请求。
4. SIP Servlet通常只是扮演一个代理的角色,最终的请求(客户端的请求)会发送到另一个已注册的SIP客户端。而HTTP Servlet会返回给客户端一个HTTP response。
5. SIP协议类似于长连接,但是一个无状态的链接,所以它可以返回个客户端多个相互独立的response,而HTTP是一个无状态的协议,一个Request对一个Response。
6. SIP 请求可以是一个异步的请求。这一点取决于上一个特性。
关于SIP Servlet的annotation。
Annotation 描述
@SipServlet 标示这是一个SIP Servlet
@SipListener 标示这个一个Sip Listener
@SipApplication 用来定义一组SIP Servlets
@SipApplicationKey 为一个SIP请求或者一个SIP session分配一个SipApplicationSession
比如:
1. @SipServlet
2. public class MyServlet extends SipServlet{
4. }
@SipServlet public class MyServlet extends SipServlet{ … }
@SipApplication 这个注释一般都用在包上。
比如
1. @SipApplication(name=”MySipApp”)Package com.example.sip;
@SipApplication(name=”MySipApp”)Package com.example.sip;
而@SipApplicationKey这个注释需要使用在方法上,而且这个方法需要满足以下条件:
1. Public method
2. Static method
3. Return a String
4. 方法的参数必须是SipServletRequest 类型
5. 传入的参数不可变
例如:
1. @SipApplication(name=”MySipApp”)
2. Package com.example.sip;
3. public class MySipApp{
4. @SipApplicationKey
5. public static String sessionKey(SipServletRequest request){
6. Return hash(request.getRequestURI()+getDomain(request.getForm()));
7. }
8. }
@SipApplication(name=”MySipApp”) Package com.example.sip; public class MySipApp{ @SipApplicationKey public static String sessionKey(SipServletRequest request){ Return hash(request.getRequestURI()+getDomain(request.getForm())); } }
在一个Sip application中只能有一个SipApplicationKey。
SIP Factory
SIP Factory 是一个Servlet Factory,也就是说所有的SIP请求进入SIP容器后,都要通过SIP Factory来创建一个Servlet实例。所以SIP Factory是整个SIP容器的入口。如果想调用容器中的其他资源,可以通过SIP Factory来调用。而调用的方法包括依赖注入和”查找”两种方式。
看例子:
1. //通过注释来调用
2. @Resource
3. SipFactory sf;
4. //通过查找的方式
5. SipFactory sf=(SipFactory)getServletContext().getAttribute(“javax.servlet.sip.SipFactory”);
//通过注释来调用 @Resource SipFactory sf; //通过查找的方式 SipFactory sf=(SipFactory)getServletContext().getAttribute(“javax.servlet.sip.SipFactory”);
SIP Session
SIP协议是一个无状态协议,所以一个response只能对应一个request(虽然一个request可以对应多个response)。也就是说多个request之间无法共享数据。
但是SIP Session提供了一种比较便捷的方式,用来存储request之间的共享数据。而这种方式非常类似于HTTP servlet中的Session对象。
但是与HTTP Session不同的是,在SIP应用中还有一个SIP ApplicationSession对象,这个东西很强大,它可以关于整个应用的session信息。
除此之外,还有个SipSessionUtil可以使用。使用方法和SIP Factory类似:
1. @Resource
2. SipSessionUtil sessionUtil;
3. //或者
4. SipSessionUtil sessionUtil=(SipSessionUtil)getServletContext().getAttribute(“javax.servlet.sip.SipSessionUtil”);
@Resource SipSessionUtil sessionUtil; //或者 SipSessionUtil sessionUtil=(SipSessionUtil)getServletContext().getAttribute(“javax.servlet.sip.SipSessionUtil”);
SIP Listeners
SIP application Listeners 就是用来监听SIP相关事件的Java Servlet listeners。它需要实现SIPServletListener接口。同时在其类上标注上Annotation用于简化部署。
比如:
1. @SipListener
2. Public class MyListener implements SipServletListener{
3. …..
4. }
@SipListener Public class MyListener implements SipServletListener{ ….. }
Back-to-Back User Agent Applications
一个back-to-back user agent(B2BUA)本身就是一个应用程序,同时它还是一个工具,很类似于代理。用于将一个客户端请求,转发给另一个客户端。而javax.servlet.sip.B2buaHelper就是一个实现这种功能的帮助类。
以上内容翻译自SUN的SIP Servlet Tutorial文档。
下面是我自己写的一个简单的sip程序。
1. package com.ohacker.sip.proxy;
2. import java.io.IOException;
3. import java.util.ArrayList;
4. import javax.servlet.ServletException;
5. import javax.servlet.sip.*;
6. import javax.servlet.sip.Address;
7. /**
8. *
9. * @author O!Hacker
10. */
11. @javax.servlet.sip.annotation.SipServlet
12. public class RegistratorServlet extends javax.servlet.sip.SipServlet {
13. public static ArrayList<Address> CLIENT_LIST=new ArrayList<Address>();
14.
15. @Override
16. protected void doInvite(SipServletRequest req) throws ServletException, IOException {
17. System.err.println("doInvite action: "+ req.getCallId());
18. Proxy proxy=req.getProxy();
19. System.err.println(req.getTo().getURI().toString());
20. proxy.proxyTo(req.getTo().getURI());
21. }
22.
23. @Override
24. protected void doRegister(SipServletRequest req) throws ServletException, IOException {
25. System.err.println("doRegister action: "+ req.getCallId());
26. System.err.println("doRegister action: "+ req.getRequestURI());
27. SipServletResponse resp=null;
28. Address address=req.getTo();
29. if(!RegistratorServlet.CLIENT_LIST.contains(address)){
30. CLIENT_LIST.add(address);
31. }
32. System.err.println(CLIENT_LIST.size());
33. resp=req.createResponse(SipServletResponse.SC_OK);
34. resp.send();
35. }
36. }