基于Tomcat7的HTML5 WebSocket 应用示例

基于Tomcat7HTML5 WebSocket 应用示例

 

作为下一代的 Web 标准,HTML5 拥有许多引人注目的新特性,如 Canvas、本地存储、多媒体编程接口、WebSocket 等等。这其中有“Web 的 TCP ”之称的 WebSocket 格外吸引开发人员的注意。WebSocket 的出现使得浏览器提供对 Socket 的支持成为可能,从而在浏览器和服务器之间提供了一个基于 TCP 连接的双向通道。Web 开发人员可以非常方便地使用 WebSocket 构建实时 web 应用

Web 应用的信息交互过程通常是客户端通过浏览器发出一个请求,服务器端接收和审核完请求后进行处理并返回结果给客户端,然后客户端浏览器将信息呈现出来,这种机制对于信息变化不是特别频繁的应用尚能相安无事,但是对于那些实时要求比较高的应用来说,比如说在线游戏、在线证券、设备监控、新闻在线播报、RSS 订阅推送等等,当客户端浏览器准备呈现这些信息的时候,这些信息在服务器端可能已经过时了。所以保持客户端和服务器端的信息同步是实时 Web 应用的关键要素,对 Web 开发人员来说也是一个难题。

在 WebSocket 规范出来之前,开发人员想实现这些实时的 Web 应用,不得不采用一些折衷的方案,其中最常用的就是轮询 (Polling) 和 Comet 技术,而 Comet 技术实际上是轮询技术的改进,又可细分为两种实现方式,一种是长轮询机制,一种称为流技术。下面我们简单介绍一下这几种技术:

轮询:

这是最早的一种实现实时 Web 应用的方案。客户端以一定的时间间隔向服务端发出请求,以频繁请求的方式来保持客户端和服务器端的同步。这种同步方案的最大问题是,当客户端以固定频率向服务器发起请求的时候,服务器端的数据可能并没有更新,这样会带来很多无谓的网络传输,所以这是一种非常低效的实时方案。

长轮询:

长轮询是对定时轮询的改进和提高,目地是为了降低无效的网络传输。当服务器端没有数据更新的时候,连接会保持一段时间周期直到数据或状态改变或者时间过期,通过这种机制来减少无效的客户端和服务器间的交互。当然,如果服务端的数据变更非常频繁的话,这种机制和定时轮询比较起来没有本质上的性能的提高。

流:

流技术方案通常就是在客户端的页面使用一个隐藏的窗口向服务端发出一个长连接的请求。服务器端接到这个请求后作出回应并不断更新连接状态以保证客户端和服务器端的连接不过期。通过这种机制可以将服务器端的信息源源不断地推向客户端。这种机制在用户体验上有一点问题,需要针对不同的浏览器设计不同的方案来改进用户体验,同时这种机制在并发比较大的情况下,对服务器端的资源是一个极大的考验。

综合这几种方案,您会发现这些目前我们所使用的所谓的实时技术并不是真正的实时技术,它们只是在用 Ajax 方式来模拟实时的效果,在每次客户端和服务器端交互的时候都是一次 HTTP 的请求和应答的过程,而每一次的 HTTP 请求和应答都带有完整的 HTTP 头信息,这就增加了每次传输的数据量,而且这些方案中客户端和服务器端的编程实现都比较复杂,在实际的应用中,为了模拟比较真实的实时效果,开发人员往往需要构造两个 HTTP 连接来模拟客户端和服务器之间的双向通讯,一个连接用来处理客户端到服务器端的数据传输,一个连接用来处理服务器端到客户端的数据传输,这不可避免地增加了编程实现的复杂度,也增加了服务器端的负载,制约了应用系统的扩展性。

本文通过一个简单例子说明在Tomcat7(注:Tomcat7之后才提供WebSocket的支持)上运行一个 WebSocket 应用

一、WebSocket

WebSocket API是下一代客户端-服务器的异步通信方法。该通信取代了单个的TCP套接字,使用wswss协议,可用于任意的客户端和服务器程序。WebSocket目前由W3C进行标准化。WebSocket已经受到Firefox 4Chrome 4Opera 10.70以及Safari 5等浏览器的支持。

WebSocket API最伟大之处在于服务器和客户端可以在给定的时间范围内的任意时刻,相互推送信息。WebSocket并不限于以Ajax(XHR)方式通信,因为Ajax技术需要客户端发起请求,而WebSocket服务器和客户端可以彼此相互推送信息;XHR受到域的限制,而WebSocket允许跨域通信。

Ajax技术很聪明的一点是没有设计要使用的方式。WebSocket为指定目标创建,用于双向推送消息。

<!--[if !supportLists]-->二、<!--[endif]-->编写servlet

自定义的servlet必须继承自org.apache.catalina.websocket.WebSocketServlet下述为完整代码:

package cn.jess.websocket;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.util.ArrayList;
import java.util.List;

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;

public class EchoServlet extends WebSocketServlet {
	/**
	 * 
	 */
	private static final long serialVersionUID = -2581942001009336822L;
	//private static final Logger log = Logger.getLogger("EchoServlet");
	private static List<MessageInbound> socketList = new ArrayList<MessageInbound>();
//	privat static final long ser
	
	private static List<WebSocketMessageInbound> connsList = new ArrayList<WebSocketMessageInbound>();
	
	protected StreamInbound createWebSocketInbound(String subProtocol,HttpServletRequest request){
		
		return new WebSocketMessageInbound();
	}
	
	public class WebSocketMessageInbound extends MessageInbound{
		protected void onClose(int status){
			super.onClose(status);
			socketList.remove(this);			
		}
		protected void onOpen(WsOutbound outbound){
			super.onOpen(outbound);
			socketList.add(this);
		}
		//@Override
		protected void onBinaryMessage(ByteBuffer message) throws IOException {
			// TODO Auto-generated method stub
			System.out.println("onBinarymessage");
		}
		@Override
		protected void onTextMessage(CharBuffer message) throws IOException {
			// TODO Auto-generated method stub
			for(MessageInbound messageInbound : socketList){
				CharBuffer buffer = CharBuffer.wrap(message);
				WsOutbound outbound = messageInbound.getWsOutbound();
				outbound.writeTextMessage(buffer);
				outbound.flush();				
			}
		}
	}
}

 

三、配置Web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 
xmlns="http://java.sun.com/xml/ns/javaee" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  <display-name></display-name>
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>  
  <servlet>
<servlet-name>websocket</servlet-name>
<servlet-class>cn.jess.websocket.EchoServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>  
        <servlet-name>websocket</servlet-name>  
        <url-pattern>/websocket</url-pattern>  
    </servlet-mapping>
</web-app>

 

四、编写index.html文件

<!DOCTYPE html>
<html>
  <head>
    <title>WebSockete Demo</title>
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="this is my page">
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    
    <!--<link rel="stylesheet" type="text/css" href="./styles.css">-->
<script type="text/javascript">
//验证浏览器是否支持WebSocket协议
if(!window.WebSocket){
alert("WebSockeet not supported by this browser!");
}
var ws;
function display(){
ws = new WebSocket("ws://localhost:8980/WebSocketHTML5/websocket");
//监听消息
ws.onmessage = function(event){
log(event.data);
}
 
//关闭WebSocket
ws.onclose = function(event){
}
//打开WebSocket
ws.onopen = function(event){
ws.send("Hello,Server");
}
ws.onerror = function(event){
}
}
var log = function(s){
if(document.readyState !== "complete"){
log.buffer.pust(s);
}else{
document.getElementById("contendId").innerHTML += (s + "\n");
}
}
function sendMsg(){
var msg = document.getElementById("messageId");
ws.send(msg.value);
}
</script>
  </head>
  
  <body οnlοad="display();">
    <div id="valueLabel"></div>
    <textarea rows="20" cols="30" id="contendId"></textarea>
    <br/>
    <input name="message" id="messageId"/>
    <button id="sendButton" onClick="javascript:sendMsg()">Send</button>
  </body>
</html>

        注意:需要拷贝Tomcat7目录下的catalina.jartomcat-coyote.jar,在部署时,需要删除程序目录下的catalina.jar,否则会导致servlet加载不成功。

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值