Tomcat7、Chrome下web socket的一个例子
先介绍一下背景吧:最近看javaEE7中可能发布的JSR规范,偶然看到JSR356,是关于web socket的,当时觉得奇怪,心说socket这几年又出了什么新东西出来了?早上了解了一下,原来也是HTML5里面的,Google工程师的这段话还是挺有吸引力的“数据的字节数急剧减少到2字节,延迟从150毫秒减少到50毫秒,实际上,这两个因素已经足以引起Google的兴趣了。通过在一个浏览器中模拟全双工连接,HTML 5 Web Socket对Web通信带来了显著的改善。”而目前一般的实时Web程序是通过Ajax轮询服务器的方式来实现的,其缺点显而易见,定时发送请求导致网络上的大量无意义数据,而且不断的连接将大量消耗服务器资源。
而Web Socket相比较的优点是:1,服务器与客户端之间交换的标头信息很小,大概只有2字节(早期版本)。2,服务器可以主动传送数据给客户端(比现有的客户端不断轮询方式好太多了)。
这概念看起来是真不错,好吧,其它废话就不多说了。上例子。
我的web服务器是从Apache tomcat网站上下载的apache-tomcat-7.0.40,浏览器用的最新的Chrome(26.0.1410.64 m)。
在Eclipse里建一个Dynamic Web Project,后台写一个继承自WebSocketServlet的Servlet
package org.study.webSocket; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.util.logging.Logger; 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; /** * @author niwei * */ // 处理WebSocket的Servlet需要继承自WebSocketServlet public class EchoServlet extends WebSocketServlet { /** * */ private static final long serialVersionUID = -328927602003370849L; // Log private Logger logger = Logger.getLogger(EchoServlet.class.getName()); @Override /** * 与7.0.27不同的,Tomcat改变了createWebSocketInbound方法的定义,增加了一个HttpServletRequest参数, * 这样我们也可以从request参数中获取更多请求方的信息 * */ protected StreamInbound createWebSocketInbound(String subProtocol, HttpServletRequest request) { logger.info("request ws servlet"); /** * 方法仍然是返回一个StreamInbound实例,这里采用实现他的子类MessageInbound * 只用实现下面四个事件处理函数(其实onClose和onOpen有缺省实现) */ return new MessageInbound() { // WebSocket关闭事件,参数status应该来自org.apache.catalina.websocket.Constants中定义常量 @Override protected void onClose(int status) { logger.info("Web Socket Closed: " + status); } // WebSocket握手完成,创建完毕,WsOutbound用于向客户端发送数据 @Override protected void onOpen(WsOutbound outbound) { logger.info("Web Socket Open!"); } // 有二进制消息数据到达,暂时没研究出这个函数什么情况下触发,js的WebSocket按理说应该只能send文本信息才对 @Override protected void onBinaryMessage(ByteBuffer buffer) throws IOException { logger.info("Binary Message Receive: " + buffer.remaining()); } // 有文本消息数据到达 @Override protected void onTextMessage(CharBuffer buffer) throws IOException { logger.info("Text Message Receive: " + buffer.remaining()); // getWsOutbound可以返回当前的WsOutbound,通过他向客户端回传数据,这里采用的是nio的CharBuffer getWsOutbound().writeTextMessage(buffer); // 模拟服务器通知浏览器,从浏览器就会看,每3秒收到1条服务器消息 for (int i = 0; i < 3; i++) { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } getWsOutbound().writeTextMessage( CharBuffer .wrap(String.valueOf(Math.random()))); } } }; } }
在web.xml里面配置一下该servlet
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> <servlet> <servlet-class>org.study.webSocket.EchoServlet</servlet-class> <servlet-name>EchoServlet</servlet-name> </servlet> <servlet-mapping> <servlet-name>EchoServlet</servlet-name> <url-pattern>/EchoServlet</url-pattern> </servlet-mapping> </web-app>
客户端访问的代码直接写在项目的欢迎页里:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>web socket example</title>
<script type="text/javascript">
var ws = null;
function startServer() {
// 设定WebSocket,注意协议是ws,请求是指向对应的WebSocketServlet的,
// localhost:8080/web-socket是你实际web项目发布的地址,
// 后面的/EchoServlet是在上面web.xml里配置的servlet访问的url
var url = "ws://localhost:8080/web-socket/EchoServlet";
// 创建WebSocket实例,chrome浏览器使用
if ('WebSocket' in window) {
ws = new WebSocket(url);
} else {
alert('Unsupported.');
return;
}
// WebSocket握手完成,连接成功的回调
// 有个疑问,按理说new WebSocket的时候就会开始连接了,如果在设置onopen以前连接成功,是否还会触发这个回调
ws.onopen = function() {
alert('Opened!');
};
// 收到服务器发送的文本消息, event.data表示文本内容
ws.onmessage = function(event) {
alert('Receive message: ' + event.data);
};
// 关闭WebSocket的回调
ws.onclose = function() {
alert('Closed!');
};
}
function sendMyMessage() {
var textMessage = document.getElementById('textMessage').value;
if (ws != null && textMessage != '') {
// 通过WebSocket想向服务器发送一个文本信息
ws.send(textMessage);
}
}
</script>
</head>
<body>
<body onload="startServer()">
<input type="text" id="textMessage" size="20" />
<input type="button" onclick="sendMyMessage()" value="Send">
</body>
</html>
关于代码的要说明的东西在注释里,不再赘述了。
直接访问项目路径即可。
项目源代码在附近里面。
上一篇: php脚本主要用于哪些领域
下一篇: 判断一个字符中是否有乱码