html5 WebSocket 教程

2015年02月16日 14:01 0 点赞 0 评论 更新于 2025-11-21 16:22

引言

在强化项目工具时,我打算实践一些 HTML5 的新技术。在设计后台交互部分时,我选择了 HTML5 的 WebSocket。经过对其基本用法的研究,我想分享一些关于 WebSocket 实践的感受。

个人认为,WebSocket 的出现是 Web 应用交互性设计的一次革新。在 WebSocket 提出之前,为了实现后台向前台推送消息的需求,人们提出了一些解决方案。这些方案利用现有的技术(如 Ajax、Iframe、Flash Player、Java Applet 等),通过一些变通的方式来实现。其基本思路要么是通过轮询的方式,让客户端浏览器不断向服务器请求数据和页面的变化;要么是通过长连接的方式,借助第三方插件来即时接收服务器的数据。

而 WebSocket 允许后台随时向前端发送文本或二进制消息。它是一种全新的协议,不属于 HTTP 无状态协议,协议名为 “ws”。这意味着一个 WebSocket 连接地址的写法会是这样:ws://localhost:8080/webSocketServer。由于 “ws” 并非 HTTP,传统的 Web 服务器不一定支持,需要服务器和浏览器同时支持,WebSocket 才能正常运行。目前,其支持情况并不普遍,需要特定的 Web 服务器和现代浏览器。以下是浏览器对 WebSocket 的支持情况:

WebSocket 应用架构特点

接下来,我们看看基于 WebSocket 设计的应用程序常见的架构方式。WebSocket 具有以下特点:

  1. 支持更多并发连接:由于其原理上的双向性,客户端的连接可以穿透有防火墙和代理的后台服务器。
  2. 减少传输消息大小:WebSocket 的通信协议并非 HTML,在新的 “ws” 通信协议设计中,大大减少了传输消息的大小,去除了传统 HTML 数据包中的许多冗余信息。瘦身之后的消息可以显著提高 Web 应用的响应性能。

实践演示

选择 Web 服务器

目前,支持 WebSocket 的 Web 服务器逐渐增多。在实践过程中,我选择了 Jetty 8.1.4。在 Jetty 的 lib 目录中,包含一个 jetty - websocket 的 JAR 包,它实现了 W3C 发布的 WebSocket 接口规范。同时,jetty - util 中也包含基于 JSON 格式的通信消息转换类,方便开发者快速开发 WebSocket 应用。

后台代码实现

在后台代码中,主要部分如下:

  1. 继承并实现 WebSocketServlet 中的 doWebSocketConnection 方法。
  2. 实现 WebSocket 接口中的 onOpenonCloseonMessage 等方法。

以下是示例代码:

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Logger;

import javax.servlet.http.HttpServletRequest;

import org.eclipse.jetty.websocket.WebSocket;
import org.eclipse.jetty.websocket.WebSocketServlet;

public class AutoAdminServlet extends WebSocketServlet {
// private static final long serialVersionUID = 1874288265454885922L;
private final Set<AutoAdminSocket> clients;
static Logger LOG = Logger.getLogger(AutoAdminServlet.class);

public AutoAdminServlet() {
clients = new HashSet<AutoAdminSocket>();
}

@Override
public WebSocket doWebSocketConnect(HttpServletRequest req, String message) {
LOG.info("Set up a web socket connection: " + message);
return new AutoAdminSocket();
}

class AutoAdminSocket implements WebSocket.OnTextMessage {
WebSocket.Connection connection;

@Override
public void onMessage(String message) {
/*
* Object json = JSON.parse(message); if(!(json instanceof Map)) return;
*
* @SuppressWarnings("unchecked") Map<String, String> map = (Map<String,
* String>)json; //TODO
*/
sendMessage(this, null, "Thanks, I received: " + message);
}

@Override
public void onClose(int code, String message) {
LOG.info("Closed and removed a client socket connection.");
clients.remove(this);
}

@Override
public void onOpen(Connection conn) {
LOG.info("Received a client socket connection.");
this.connection = conn;
clients.add(this);
sendMessage(this, "open", "sample data");
}
}

void sendMessage(AutoAdminSocket client, String action, String message) {
try {
if (message == null || message.isEmpty()) {
message = "n/a";
}

if (action != null) {
message = "action: " + action + ", data: " + message;
}

client.connection.sendMessage(message);
} catch (IOException ex) {
ex.printStackTrace();
}
}
}

前台页面代码实现

前台页面代码部分,主要需要做好以下几点:

  1. 在 JavaScript 中判断浏览器是否支持 WebSocket,并提供友好提示或备用方案。
  2. 创建 WebSocket 的 JavaScript 对象,并谨慎管理它。避免滥用,不断与服务器建立 WebSocket 连接,一般一个浏览器终端维护一个连接即可,逻辑的多样性可以通过命令模式来丰富。
  3. 当浏览器需要主动与服务器通信时,调用 WebSocket API 中的 send 方法。
  4. 当服务器主动推送数据到浏览器时,在 onMessage 方法中处理多样的业务逻辑。

以下是示例代码:

var log = function(s) {
if (document.readyState !== "complete") {
log.buffer.push(s);
} else {
document.getElementById("output").innerHTML += (s + "\n");
}
}

log.buffer = [];

var socket = null;
function init() {
window.WebSocket = window.WebSocket || window.MozWebSocket;
if (!window.WebSocket) {
log("WebSocket not supported by this browser");
return;
}

var webSocket = new WebSocket("ws://127.0.0.1:8080/pulsenet/auto");
webSocket.onopen = onopen;
webSocket.onclose = onclose;
webSocket.onmessage = onmessage;

socket = webSocket;
}

function onopen() {
log("Open a web socket.");
}

function onclose() {
log("Close a web socket.");
}

function onmessage(evt) {
var data = evt.data;
if (!data) return;

log(data);

data = JSON.parse(data);
if (!data) return;
}

function send() {
socket.send("Hello web socket server!");
}

通过上述的后台和前台代码示例,我们可以看到如何使用 WebSocket 实现前后台的通信。在实际开发中,可以根据具体需求对代码进行扩展和优化。

作者信息

boke

boke

共发布了 3994 篇文章