现很多网站为了实现即时通讯,所用的技术都是轮询(polling)。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发
出HTTP request,然后由服务器返回最新的数据给客服端的浏览器。这种传统的HTTP request 的模式带来很明显的缺点 – 浏
览器需要不断的向服务器发出请求,然而HTTP request 的header是非常长的,里面包含的数据可能只是一个很小的值,这样会占
用很多的带宽。WebSocket提供了一个受欢迎的技术,以替代我们过去几年一直在用的Ajax技术。
一、什么是WebSocket API?
WebSocket API是下一代客户端-服务器的异步通信方法。该通信取代了单个的TCP套接字,使用ws或wss协议,可用于任意的
客户端和服务器程序。WebSocket目前由W3C进行标准化。WebSocket已经受到Firefox 4、Chrome 4、Opera 10.70以及Safari 5等
浏览器的支持。
WebSocket API最伟大之处在于服务器和客户端可以在给定的时间范围内的任意时刻,相互推送信息。WebSocket并不限于以
Ajax(或XHR)方式通信,因为Ajax技术需要客户端发起请求,而WebSocket服务器和客户端可以彼此相互推送信息;XHR受到域
的限制,而WebSocket允许跨域通信。
Ajax技术很聪明的一点是没有设计要使用的方式。WebSocket为指定目标创建,用于双向推送消息。
那么我就开始我在项目中对websocket的使用。这里我创建了一个基于maven 的web Project
基于J2EE7的jar以及websocket的核心api。websocket必须基于tomcat7.4以上版本,这里使用了tomcat8
只需要一个 WebSocketTest.java 和 一个 index.jsp文件即可实现:
1 package com.cn.zym.websocket;
2
3 import java.io.IOException;
4 import java.util.concurrent.CopyOnWriteArraySet;
5
6 import javax.websocket.OnClose;
7 import javax.websocket.OnMessage;
8 import javax.websocket.OnOpen;
9 import javax.websocket.OnError;
10 import javax.websocket.server.ServerEndpoint;
11
12 /**
13 * @ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端,
14 * 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端
15 */
16 @ServerEndpoint("/websocket")
17 public class WebSocketTest {
18 //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
19 private static int onlineCount = 0;
20
21 //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
22 // 若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识
23 private static CopyOnWriteArraySet<WebSocketTest> webSocketSet = new CopyOnWriteArraySet<WebSocketTest>();
24
25 //与某个客户端的连接会话,需要通过它来给客户端发送数据
26 private Session session;
27
28 /**
29 * 连接建立成功调用的方法
30 * @param session 可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据
31 */
32 @OnOpen
33 public void onOpen(Session session){
34 this.session = session;
35 webSocketSet.add(this); //加入set中
36 addOnlineCount(); //在线数加1
37 System.out.println("有新连接加入!当前在线人数为" + getOnlineCount());
38 }
39
40 /**
41 * 连接关闭调用的方法
42 */
43 @OnClose
44 public void onClose(){
45 webSocketSet.remove(this); //从set中删除
46 subOnlineCount(); //在线数减1
47 System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount());
48 }
49
50 /**
51 * 收到客户端消息后调用的方法
52 * @param message 客户端发送过来的消息
53 * @param session 可选的参数
54 */
55 @OnMessage
56 public void onMessage(String message, Session session) {
57 System.out.println("来自客户端的消息:" + message);
58 //群发消息
59 for(WebSocketTest item: webSocketSet){
60
61 try {
62 item.sendMessage(message);
63 } catch (IOException e) {
64 e.printStackTrace();
65 continue;
66 }
67 }
68 }
69
70 /**
71 * 发生错误时调用
72 * @param session
73 * @param error
74 */
75 @OnError
76 public void onError(Session session, Throwable error){
77 System.out.println("发生错误");
78 error.printStackTrace();
79 }
80
81 /**
82 * 这个方法与上面几个方法不一样。没有用注解,是根据自己需要添加的方法。
83 * @param message
84 * @throws IOException
85 */
86 public void sendMessage(String message) throws IOException{
87 this.session.getBasicRemote().sendText(message);
88 //this.session.getAsyncRemote().sendText(message);
89 }
90
91 public static synchronized int getOnlineCount() {
92 return onlineCount;
93 }
94
95 public static synchronized void addOnlineCount() {
96 WebSocketTest.onlineCount++;
97 }
98
99 public static synchronized void subOnlineCount() {
100 WebSocketTest.onlineCount--;
101 }
102 }
需要注意一点,在创建WebSocket实例的时候改地址目前的拼接方式为:ws://localhost:8080/设置好的项目访问规则/@ServerEndpoint注解的值
批注:
Websockets - wss on http vs. wss on https
<%@ page language="java" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
<title>Java后端WebSocket的Tomcat实现</title>
</head>
<body>
Welcome<br/><input id="text" type="text"/>
<button onclick="send()">发送消息</button>
<hr/>
<button onclick="closeWebSocket()">关闭WebSocket连接</button>
<hr/>
<div id="message"></div>
</body>
<script type="text/javascript">
var websocket = null;
//判断当前浏览器是否支持WebSocket
if ('WebSocket' in window) {
websocket = new WebSocket("ws://localhost:8080/jws/websocket");
//websocket = new WebSocket("ws://echo.websocket.org", ["com.kaazing.echo","example.imaginary.protocol"])
}
else {
alert('当前浏览器 Not support websocket')
}
//连接发生错误的回调方法
websocket.onerror = function () {
setMessageInnerHTML("WebSocket连接发生错误");
};
//连接成功建立的回调方法
websocket.onopen = function () {
setMessageInnerHTML("WebSocket连接成功");
}
//接收到消息的回调方法
websocket.onmessage = function (event) {
setMessageInnerHTML(event.data);
}
//连接关闭的回调方法
websocket.onclose = function () {
setMessageInnerHTML("WebSocket连接关闭");
}
//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function () {
closeWebSocket();
}
//将消息显示在网页上
function setMessageInnerHTML(innerHTML) {
document.getElementById('message').innerHTML += innerHTML + '<br/>';
}
//关闭WebSocket连接
function closeWebSocket() {
websocket.close();
}
//发送消息
function send() {
var message = document.getElementById('text').value;
websocket.send(message);
}
</script>
</html>