我正在努力让SIP servlet聊天服务器工作,together with the textclient found here。
当我使用2个客户端向对方发送消息(点对点)时,一切顺利。但是当我将一个或多个客户端与我的服务器一起使用时,我必须等待32秒,然后服务器才能在doMessage()
方法中获取任何新消息。
我正在使用Netbeans和Sailfin作为我的SIP服务器。我正在调查Sailfin中的请求或响应之间是否存在某种限制或可配置的延迟或超时?
如果需要,我可以发布服务器代码。
由于
答案 0 :(得分:2)
这是服务器的代码,我稍后会尝试进行wireshark跟踪。
public class ChatroomSipServlet extends SipServlet {
public final static String USER_LIST = "userList";
public final static String CHATROOM_SERVER_NAME = "chatroomservername";
public String serverAddress;
public SipFactory factory;
@Override
public void init(ServletConfig servletConfig) throws ServletException {
super.init(servletConfig);
System.out.println("Chatroom sip servlet is gestart!");
try {
factory = (SipFactory) getServletContext().getAttribute("javax.servlet.sip.SipFactory");
System.out.println("Sip Factory: " + factory);
} catch (Exception e) {
throw new ServletException("Factory probleem!", e);
}
getServletContext().setAttribute(USER_LIST, new ArrayList<String>());
serverAddress = getServletConfig().getInitParameter(CHATROOM_SERVER_NAME);
System.out.println("serverAddress is: " + serverAddress);
}
@Override
public void destroy() {
try {
sendToAll(serverAddress, "Server sluit af!");
} catch (Throwable e) {
e.printStackTrace();
}
super.destroy();
}
protected void doMessage(SipServletRequest request) throws ServletException, IOException {
System.out.println(getDateTime() + " Bericht ontvangen");
request.createResponse(SipServletResponse.SC_OK).send();
String message = request.getContent().toString();
String from = ((SipURI) request.getFrom().getURI()).toString();
if (message.equalsIgnoreCase("/quit")) {
sendToUser(from, "Bye");
removeUser(from);
return;
}
if (!containsUser(from)) {
sendToUser(from, "Welkom in de chatroom. Typ '/quit' om af te sluiten.");
addUser(from);
}
if (message.equalsIgnoreCase("/who")) {
String users = "Lijst van de gebruikers:\n";
List<String> list = (List<String>) getServletContext().getAttribute(USER_LIST);
for (String user : list) {
users += user + "\n";
}
sendToUser(from, users);
return;
}
if (message.equalsIgnoreCase("/join")) {
return;
}
sendToAll(from, message);
}
protected void doErrorResponse(SipServletResponse response) throws ServletException, IOException {
// String receiver = response.getTo().toString();
String receiver = ((SipURI) response.getTo().getURI()).toString();
System.out.println(getDateTime() + " Errorresponse voor " + receiver);
removeUser(receiver);
}
protected void doSuccessResponse(SipServletResponse response) throws ServletException, IOException {
response.getApplicationSession().invalidate();
}
private void sendToAll(String from, String message) throws ServletParseException, IOException {
List<String> list = (List<String>) getServletContext().getAttribute(USER_LIST);
for (String user : list) {
SipApplicationSession session = factory.createApplicationSession();
System.out.println(getDateTime() + " Session created voor " + user);
SipServletRequest request = factory.createRequest(session, "MESSAGE", serverAddress, user);
String msg = from + " stuurt: \n" + message;
request.setContent(msg.getBytes(), "text/plain");
request.send();
}
}
private void sendToUser(String to, String message) throws ServletParseException, IOException {
SipApplicationSession session = factory.createApplicationSession();
SipServletRequest request = factory.createRequest(session, "MESSAGE", serverAddress, to);
request.setContent(message.getBytes(), "text/plain");
request.send();
}
private boolean containsUser(String from) {
List<String> list = (List<String>) getServletContext().getAttribute(USER_LIST);
return list.contains(from);
}
private void addUser(String from) {
List<String> list = (List<String>) getServletContext().getAttribute(USER_LIST);
list.add(from);
}
private void removeUser(String from) {
System.out.println(getDateTime() + " " + from + " wordt verwijderd uit de lijst.");
List<String> list = (List<String>) getServletContext().getAttribute(USER_LIST);
list.remove(from);
}
@Override
protected void doRegister(SipServletRequest req) throws ServletException, IOException {
System.out.println("Register request ontvangen: " + req.getTo());
int response = SipServletResponse.SC_OK;
SipServletResponse resp = req.createResponse(response);
resp.send();
}
private String getDateTime() {
DateFormat dateFormat = new SimpleDateFormat("[" + "HH:mm:ss" + "]");
Date date = new Date();
return dateFormat.format(date);
}
}
和sip.xml
<sip-app>
<app-name>sip.chatvoorbeeld.ChatServer</app-name>
<display-name>Chatroom Sip Servlet</display-name>
<description>Chatroom Sip Servlet</description>
<servlet-selection>
<main-servlet>
ChatroomSipServlet
</main-servlet>
</servlet-selection>
<session-config>
<session-timeout>5</session-timeout>
</session-config>
<servlet>
<servlet-name>ChatroomSipServlet</servlet-name>
<display-name>ChatroomSipServlet</display-name>
<description>Chatroom SIP servlet</description>
<servlet-class>
sip.chatvoorbeeld.ChatroomSipServlet
</servlet-class>
<init-param>
<param-name>chatroomservername</param-name>
<param-value>sip:chatserver@192.168.56.1:5060</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
</sip-app>
我还尝试了一个空的servlet,只用一个doMessage()
方法打印出“收到的消息”。同样的32秒延迟...
Wireshark给了我:
我将消息“test”发送到服务器:
MESSAGE sip:chatserver@192.168.56.1:5060;transport=udp SIP/2.0
Call-ID: aba00c2646a9b4e6df3b15df19dbf58d@192.168.56.101
CSeq: 1 MESSAGE
From: "bobby" <sip:bobby@192.168.56.101:5095>;tag=textclientv1.0
To: "chatserver" <sip:chatserver@192.168.56.1:5060>
Via: SIP/2.0/UDP 192.168.56.101:5095;branch=branch1
Max-Forwards: 70
Contact: "bobby" <sip:bobby@192.168.56.101:5095>
Content-Type: text/plain
Content-Length: 4
test
服务器发回:
SIP/2.0 200 OK
Content-Length: 0
To: "chatserver"<sip:chatserver@192.168.56.1:5060>;tag=g9vdns7u-e
Cseq: 1 MESSAGE
Via: SIP/2.0/UDP 192.168.56.101:5095;branch=branch1
From: "bobby"<sip:bobby@192.168.56.101:5095>;tag=textclientv1.0
Call-Id: aba00c2646a9b4e6df3b15df19dbf58d@192.168.56.101
Server: Glassfish_SIP_2.0.0
MESSAGE sip:bobby@192.168.56.101:5095 SIP/2.0
Max-Forwards: 69
Content-Length: 43
To: <sip:bobby@192.168.56.101:5095>
Cseq: 1 MESSAGE
Via: SIP/2.0/UDP 192.168.56.1:5060;branch=z9hG4bKdaacb7673c871796474ca951221a6643db6c
Content-Type: text/plain
Call-Id: 192.168.56.1_11_6595680936174578736
From: <sip:chatserver@192.168.56.1:5060>;tag=g9vdns7u-g
sip:bobby@192.168.56.101:5095 stuurt:
test
然后我的客户再次回答:
SIP/2.0 200 OK
To: <sip:bobby@192.168.56.101:5095>;tag=888
CSeq: 1 MESSAGE
Via: SIP/2.0/UDP 192.168.56.1:5060;branch=z9hG4bKdaacb7673c871796474ca951221a6643db6c;received=192.168.56.1
Call-ID: 192.168.56.1_11_6595680936174578736
From: <sip:chatserver@192.168.56.1:5060>;tag=g9vdns7u-g
Content-Length: 0
到目前为止一切顺利,一切顺利。 但现在我向服务器“test2”发送第二条消息,我得到了这个:
客户端到服务器:
MESSAGE sip:chatserver@192.168.56.1:5060;transport=udp SIP/2.0
Call-ID: 95ad65365378b9b6b5bd7ad3629f7b02@192.168.56.101
CSeq: 1 MESSAGE
From: "bobby" <sip:bobby@192.168.56.101:5095>;tag=textclientv1.0
To: "chatserver" <sip:chatserver@192.168.56.1:5060>
Via: SIP/2.0/UDP 192.168.56.101:5095;branch=branch1
Max-Forwards: 70
Contact: "bobby" <sip:bobby@192.168.56.101:5095>
Content-Type: text/plain
Content-Length: 5
test2
然后服务器确实响应:
SIP/2.0 200 OK
Content-Length: 0
To: "chatserver"<sip:chatserver@192.168.56.1:5060>;tag=g9vdns7u-e
Cseq: 1 MESSAGE
Via: SIP/2.0/UDP 192.168.56.101:5095;branch=branch1
From: "bobby"<sip:bobby@192.168.56.101:5095>;tag=textclientv1.0
Call-Id: aba00c2646a9b4e6df3b15df19dbf58d@192.168.56.101
Server: Glassfish_SIP_2.0.0
然后通讯停止了......我得到了200 OK,但我的println()
方法中的doMessage()
未通过。
答案 1 :(得分:1)
32秒是事务的正常超时(在RFC3261中表示为64 * T1,其中T1的默认值为500ms。)
我没有直接想法解决您的问题,除了超时很可能不是SailFin中的错误配置。所以请提供wireshark跟踪和服务器代码!
答案 2 :(得分:0)
要回答我自己的问题,如果有人遇到同样的问题,我发现这是textclient中的一个错误,违反了RFC 3261的8.1.1.7节。
分支参数值必须是 所有人都有独特的空间和时间 UA发送的请求。该 这条规则的例外是CANCEL和 确认非2xx响应。如 下面讨论一个CANCEL请求 具有相同的分支值 参数作为取消的请求。 如第17.1.1.3节所述, 对于非2xx响应的ACK也将 具有与INVITE相同的分支ID 它承认的回应。
分支的唯一性属性 ID参数,方便其使用 事务ID,不是RFC的一部分 2543。
元素插入的分支ID 符合此规范必须 总是以角色开头 “z9hG4bK”。
SipLayer.java中的以下行
ViaHeader viaHeader = headerFactory.createViaHeader(getHost(),
getPort(), "udp", "branch1");
将使用“branch1”参数创建每条消息。使此参数唯一可以解决问题。