一、简介:
规范的目标是在浏览器中实现和服务器端双向通信。本文基于resin4使用WebSocket实现了一个简单的聊天室demo。
WebSocket需要浏览器首先向服务器发出建立链接请求,然后服务端发出回应。是一个简单的握手过程。握手成功后,双方的链接也就建立成功了,之后就可以直接发送消息了。握手消息头如下:
Request Headers::
Connection:Upgrade
Host:192.168.33.247
Origin:http://localhost
Sec-WebSocket-Key:k685VzFQc/sTHdSZhlwLGg==
Sec-WebSocket-Version:13
Upgrade:websocket
-----------------------
Response Headers::
Connection:Upgrade
Content-Length:0
Date:Wed, 21 Nov 2012 08:52:42 GMT
Sec-WebSocket-Accept:A95+L06MV5iDruLH0K1zgINLHoI=
Server:Resin/4.0.32
Upgrade:websocket
主要用的核心类包括:
(1) WebSocketServletRequest :建立链接(握手)
(2) WebSocketContext :发送消息
(3) WebSocketListener :监听消息
二、resin4集群配置
因为测试的时候首先是利用resin4部署了一个resin集群,所以这里首先将resin4的集群部署介绍下。
Resin4支持快速配置cluster,通过简单的配置即可实现一个resin集群。最简单的配置只需要修改resin. Properties中的app_servers配置项。将集群的配置依照顺序填进上去即可:
测试使用了三台机器,示例配置如下:
app_servers : 10.22.32.185 10.22.32.186 10.22.32.187
注意:三台机器的配置项需要一致
相关命令示例:
(1) 启动: ~/resin/bin/resin.sh –conf conf/resin.xml start
(2) 注意:在启动的时候,有时候会发现启动不成功的情况,可以单台启动,比如:
~/resin/bin/resin.sh –conf conf/resin.xml -server app-0 start
其中app-0代表集群中的第一台机器,其他类推
(3) 部署:~/resin/bin/resinctl deploy /tmp/test.war
在实际中部署完还需要使用:~/resin/bin/resinctl web-app-start test 命令启动下。 www.it165.net
部署并启动成功后,一个resin集群就配置完成了。
三、聊天室demo
这里基于resin4+websocket实现了一个聊天室的demo,主要逻辑如下:
(1) 浏览器发起建立socket的链接
(2) 服务端servlet建立链接,并将相关的socket保存到一个map中
(3) 客户端发送聊天信息
(4) 服务器监听到消息后,将消息广播出去。
主要实现了两个类:
1、MyServlet类:建立链接
其中service主要是功能是建立websocket练级并将链接保存
示例代码如下:
import com.caucho.websocket.WebSocketContext;
import com.caucho.websocket.WebSocketServletRequest;
import com.caucho.websocket.WebSocketListener;
.....
public class MyServlet extends HttpServlet {
private static Hashtable map_socket = new Hashtable(50);
public void service(HttpServletRequest req,HttpServletResponse res) throws IOException, ServletException
{
String protocol = req.getHeader("Sec-WebSocket-Protocol");
WebSocketListener listener;
listener = new MyListener();
//res.setHeader("Sec-WebSocket-Protocol", "my-protocol");
WebSocketServletRequest wsReq = (WebSocketServletRequest) req;
WebSocketContext webSocketContext = wsReq.startWebSocket(listener);
map_socket.put(webSocketContext.hashCode(),webSocketContext);
}
public static HashtablegetSockList()
{
return map_socket;
}
}
2、 MyListener:监听并广播消息
监听了onStart、onReadText、onDisconnect三个事件
示例代码如下:
public class MyListener implements WebSocketListener {
@Override
public void onStart(WebSocketContext webSocketContext) throws IOException {
PrintWriter out = webSocketContext.startTextMessage();
out.print("start ok");
out.close();
}
@Override
public void onReadText(WebSocketContext webSocketContext, Reader reader) throws IOException {
PrintWriter out = null;
int ch;
String text = "";
while ((ch = reader.read()) >= 0) {
text = text+(char)ch;
}
int id = webSocketContext.hashCode();
Hashtable map = MyServlet.getSockList();
Iterator iter = map.entrySet().iterator();
while (iter.hasNext())
{
Map.Entry entry = (Map.Entry)iter.next();
WebSocketContext w = (WebSocketContext)entry.getValue();
out = w.startTextMessage();
out.print(id + ": " + text);
out.close();
}
reader.close();
}
@Override
public void onDisconnect(WebSocketContext webSocketContext) throws IOException {
Hashtable map = MyServlet.getSockList();
map.remove(webSocketContext.hashCode());
//To change body of implemented methods use File | Settings | File Templates.
}
}
3、测试页面的代码如下:
var socket;
function display() {
var valueLabel = document.getElementById(“valueLabel”);
valueLabel.innerHTML = “”;
var ws = new WebSocket(
“ws://localhost/www/MyServlet”);
ws.onmessage = function(evt) {
valueLabel.innerHTML = valueLabel.innerHTML + “
” + evt.data;
};
ws.onclose = function(evt) {
valueLabel.innerHTML = “onClose”;
};
ws.onopen = function() {
ws.send(“Hello, All guys”);
};
socket = ws;
}
function say()
{
socket.send(speak.value);
}