您的位置:首页 > 运维架构 > Tomcat

Tomcat7 Websocket入门贴

2015-12-16 17:07 537 查看
传统的J2EE程序,浏览器端并没有推送机制,如果浏览器想要实时获取服务端的最新信息,那么必须通过轮询的方式。很显然轮询方式既浪费http带宽,又难以保证实时性。手机端的消息推送很方便,很好用。比如百度提供的百度云推送方案,google的GCM推送,apple的apns推送,基于这些推送服务,我们可以很容易构建出手机端的实时应用。websocket的引入,就是为了让浏览器也能像手机一样,被动接受服务端的推送信息。

HTML5中引入了WebSocket,浏览器的编码是很容易的。我写了一个简单的模拟登录、登出、发消息的界面:



<head>
<script src="jquery-1.11.1.min.js"></script>
<script>
$(function(){

// 浏览器上的websocket对象,用来和服务端通信.
var socket = null;

$("#login").click(function(){
var userName = $("#userName").val();
if($.trim(userName) == "")
{
return;
}

// 创建websocket对象
socket = new WebSocket('ws://localhost:8080/websocket/chat?userName='+userName);
registerEvent();
});

$("#logout").click(function(){
socket.close();
});

$("#send").click(function(){
socket.send($("#message").val());
});

function registerEvent()
{
socket.onopen = function(event) {
$("#messagePanel").append("<div>websocket open successfully.</div>");
}

socket.onmessage = function(event) {
$("#messagePanel").append("<div>msg="+event.data+"</div>");
};

socket.onclose = function(event) {
$("#messagePanel").append("<div>websocket close successfully.</div>");
};
}

});

</script>
<style>
.card{
margin:20px;
}
</style>
</head>
<body>
<div class="card">
userName:<input id="userName" value="" placeholder="input your name"/>
<button id="login">login</button>
<button id="logout">logout</button>
</div>
<div class="card">
message:<input id="message" value="" placeholder="input your message"/>
<button id="send">send</button>
</div>

<div class="card" id="messagePanel">

</div>
</body>


可以看到客户端的编程是很容易的,我们主要看下服务端的编程。

package aty.net;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;

import org.apache.catalina.websocket.MessageInbound;
import org.apache.catalina.websocket.StreamInbound;
import org.apache.catalina.websocket.WebSocketServlet;
import org.apache.catalina.websocket.WsOutbound;

@WebServlet(name = "chat", urlPatterns = "/chat")
public class ChatWebSocket extends WebSocketServlet {

private static final String GUEST_PREFIX = "Guest";

private final Set<ChatMessageInbound> connections = new CopyOnWriteArraySet<ChatMessageInbound>();

@Override
protected StreamInbound createWebSocketInbound(String subProtocol,
HttpServletRequest request) {
return new ChatMessageInbound(request.getParameter("userName"));
}

private final class ChatMessageInbound extends MessageInbound {

private final String nickname;

private ChatMessageInbound(String name) {
this.nickname = name;
}

@Override
protected void onOpen(WsOutbound outbound) {
connections.add(this);

System.out.println(nickname + "has joined.");
broadcast(nickname + " has joined.");
}

@Override
protected void onClose(int status) {
connections.remove(this);
System.out.println(nickname + "has leaved.");
broadcast(nickname + " has leaved.");
}

@Override
protected void onBinaryMessage(ByteBuffer buffer) throws IOException {

}

@Override
protected void onTextMessage(CharBuffer buffer) throws IOException {

System.out.println(nickname + " say:" + buffer.toString());
broadcast(nickname + " say:" + buffer.toString());
}

private void broadcast(String message) {
for (ChatMessageInbound connection : connections) {
try {
CharBuffer buffer = CharBuffer.wrap(message);
connection.getWsOutbound().writeTextMessage(buffer);
} catch (IOException ignore) {
}
}
}
}
}
可以看到我们使用了WebSocketServlet接受请求,使用MessageInbound来处理真正的websocket连接。

为了保证上面的java代码编译通过,需要引入catalina.jar、servlet-api.jar、tomcat-coyote.jar。需要特别注意:这3个包只是编译需要,实际运行的时候不能将这3个jar放到我们的war包中。因为tomcat7运行环境,自带的就有这些jar。我实验过:如果将这些jar包放到我们自己war包下,会导致创建websocket失败。



接下来我们可以在tomcat7下运行上面的代码,打开1个浏览器客户端。



现在我们打开第二个客户端,操作步骤同第一个客户端一样。



现在我们看下第一个客户端:



很明显:第一个客户端能够收到消息,这就是推送,非常方便。基于websocket推送,我们能够更好、更容易地构建监控等实时应用的程序。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息