65.9K
CodeProject 正在变化。 阅读更多。
Home

您的网站已准备好使用 WebSockets

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.86/5 (4投票s)

2012年6月8日

CPOL

7分钟阅读

viewsIcon

31469

本教程提供了对 W3C WebSocket API 及其底层 WebSocket 协议的简单介绍。

30 天开发一个 Windows 8 应用

WebSockets 已经稳定,随时可供开发者开始创建创新的应用程序和服务。本教程提供了对 W3C WebSocket API 及其底层 WebSocket 协议的简单介绍。更新的 Flipbook 演示使用了最新版本的 API 和协议。

工作组已取得重大进展,WebSocket API 已成为 W3C 候选推荐。Internet Explorer 10 实现的是此版本的规范。您可以在此处了解该规范的演变。

WebSockets 使 Web 应用程序能够在浏览器中提供实时通知和更新。开发者在处理浏览器最初的 HTTP 请求-响应模型限制时遇到了问题,该模型并非为实时场景而设计。WebSockets 使浏览器能够与服务建立双向、全双工的通信通道。双方都可以使用此通道立即向另一方发送数据。现在,从社交网络和游戏到金融网站,各种网站都可以提供更好的实时场景,理想情况下,可以在不同浏览器中使用相同的标记。

使用回显示例介绍 WebSocket API

下面的代码片段使用 ASP.NET 的 System.Web.WebSockets 命名空间创建的简单回显服务器,以回显从应用程序发送的文本和二进制消息。该应用程序允许用户输入文本发送并作为文本消息回显,或绘制图片作为二进制消息发送并回显。

有关允许您试验 WebSocket 和 HTTP 轮询之间延迟和性能差异的更复杂示例,请参阅 Flipbook 演示

连接到 WebSocket 服务器的详细信息

这个简单的解释基于应用程序和服务器之间的直接连接。如果配置了代理,则 IE10 会通过向代理发送 HTTP CONNECT 请求来启动该过程。

创建 WebSocket 对象时,客户端和服务器之间会进行握手以建立 WebSocket 连接。

IE10 通过向服务器发送 HTTP 请求来启动此过程

GET /echo HTTP/1.1
Host: example.microsoft.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://microsoft.com
Sec-WebSocket-Version: 13

让我们看一下此请求的每个部分。

连接过程以标准的 HTTP GET 请求开始,该请求允许请求穿过防火墙、代理和其他中间件。

GET /echo HTTP/1.1
Host: example.microsoft.com

HTTP Upgrade 标头请求服务器将应用程序层协议从 HTTP 切换到 WebSocket 协议。

Upgrade: websocket
Connection: Upgrade

服务器会转换其响应中 Sec-WebSocket-Key 标头的值,以表明它理解 WebSocket 协议。

Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==

Origin 标头由 IE10 设置,以允许服务器强制执行基于源的安全策略

Sec-WebSocket-Version: 13

Sec-WebSocket-Version 标头标识了请求的协议版本。版本 13 是 IETF 提议标准中的最终版本。

Sec-WebSocket-Version: 13

如果服务器接受升级应用程序层协议的请求,它将返回一个 HTTP 101 Switching Protocols 响应。

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade

为了证明其理解 WebSocket 协议,服务器会对其从客户端请求中收到的 Sec-WebSocket-Key 执行标准化的转换,并在 Sec-WebSocket-Accept 标头中返回结果。

Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

然后,IE10 将比较 Sec-WebSocket-Key 和 Sec-WebSocket-Accept,以验证服务器是 WebSocket 服务器,而不是一个自命不凡的 HTTP 服务器。

客户端握手在 IE10 和服务器之间建立了基于 TCP 的 HTTP 连接。在服务器返回其 101 响应后,应用程序层协议将从 HTTP 切换到 WebSocket,后者使用之前建立的 TCP 连接。

此时 HTTP 完全被排除在外。使用轻量级的 WebSocket 线协议,现在任何一方都可以随时发送或接收消息。

编程连接到 WebSocket 服务器

WebSocket 协议定义了 两个新的 URI 方案,它们类似于 HTTP 方案。

  • "ws:" "//" host [ ":" port ] path [ "?" query ] 模仿 "http:" 方案。其默认端口为 80。它用于不安全(未加密)的连接。
  • "wss:" "//" host [ ":" port ] path [ "?" query ] 模仿 "https:" 方案。其默认端口为 443。它用于通过 传输层安全隧道传输的安全连接。

当存在代理或网络中间件时,安全连接成功的可能性会更高,因为中间件不太愿意尝试转换安全流量。

以下代码片段建立了一个 WebSocket 连接

var host = "ws://example.microsoft.com";
var socket = new WebSocket(host);

ReadyState – 准备… 就绪… 开始…!

WebSocket.readyState 属性表示连接的状态:CONNECTING、OPEN、CLOSING 或 CLOSED。当 WebSocket 首次创建时,readyState 设置为 CONNECTING。当连接建立时,readyState 设置为 OPEN。如果连接未能建立,则 readyState 设置为 CLOSED。

注册 Open 事件

要接收连接已创建的通知,应用程序必须注册 open 事件。

socket.onopen = function (openEvent) {
document.getElementById("serverStatus").innerHTML = 'Web Socket State::' + 'OPEN';
};,

发送和接收消息的详细信息

在成功握手后,应用程序和 WebSocket 服务器可以交换 WebSocket 消息。消息由一个或多个消息片段或数据“帧”组成。

每个帧包含的信息,例如:

  • 帧长度
  • 消息的第一帧中的消息类型(二进制或文本)
  • 一个标志 (FIN),指示这是否是消息的最后一帧

IE10 在将帧传递给脚本之前,会将其重新组装成一条完整的消息。

编程发送和接收消息

send API 允许应用程序将消息作为 UTF-8 文本、ArrayBuffers 或 Blobs 发送到 WebSocket 服务器。

例如,此代码片段检索用户输入的文本,并将其作为 UTF-8 文本消息发送到服务器以进行回显。它验证 WebSocket 是否处于 OPEN 状态。

function sendTextMessage() {
    if (socket.readyState != WebSocket.OPEN)
        return;
    var e = document.getElementById("textmessage");
    socket.send(e.value);
}

此代码片段检索用户在画布上绘制的图像,并将其作为二进制消息发送到服务器。

function sendBinaryMessage() {
    if (socket.readyState != WebSocket.OPEN)
        return;
    var sourceCanvas = document.getElementById('source');
    // msToBlob returns a blob object from a canvas image or drawing
    socket.send(sourceCanvas.msToBlob());
    // ...
}

注册 Message 事件

要接收消息,应用程序必须注册 message 事件。事件处理程序会收到一个 MessageEvent,其中包含 MessageEvent.data 中的数据。数据可以作为文本或二进制消息接收。

当收到二进制消息时,WebSocket.binaryType 属性控制是将消息数据作为 Blob 还是 ArrayBuffer 数据类型返回。该属性可以设置为“blob”或“arraybuffer”。

下面的示例使用默认值,即“blob”。

此代码片段接收来自 websocket 服务器的回显图像或文本。如果数据是 Blob,则返回的是图像并绘制在目标画布上;否则,返回的是 UTF-8 文本消息并显示在文本字段中。

socket.onmessage = function (messageEvent) {
    if (messageEvent.data instanceof Blob) {
        var destinationCanvas = document.getElementById('destination');
        var destinationContext = destinationCanvas.getContext('2d');
        var image = new Image();
        image.onload = function () {
            destinationContext.clearRect(0, 0, destinationCanvas.width, destinationCanvas.height);
            destinationContext.drawImage(image, 0, 0);
        }
        image.src = URL.createObjectURL(messageEvent.data);
    } else {
        document.getElementById("textresponse").value = messageEvent.data;
    }
};

关闭 WebSocket 连接的详细信息

与打开握手类似,也存在关闭握手。任一端(应用程序或服务器)都可以发起此握手。

一种特殊类型的帧——关闭帧——会发送到另一端。关闭帧可能包含可选的状态代码和关闭原因。协议定义了一组适当的 状态代码值。关闭帧的发送者在发送关闭帧后不得发送其他应用程序数据。

当另一端收到关闭帧时,它会用自己的关闭帧进行响应。它可以在响应关闭帧之前发送挂起的消息。

编程关闭 WebSocket 并注册 Close 事件

应用程序使用 close API 在打开的连接上发起关闭握手。

socket.close(1000, "normal close");

要接收连接已关闭的通知,应用程序必须注册 close 事件。

socket.onclose = function (closeEvent) {
    document.getElementById("serverStatus").innerHTML = 'Web Socket State::' + 'CLOSED';
};

close API 接受两个可选参数:由协议定义的 status code 和 description。status code 必须是 1000 或 3000 到 4999 之间的值。执行 close 时,readyState 属性设置为 CLOSING。在 IE10 收到服务器的关闭响应后,readyState 属性设置为 CLOSED,并触发 close 事件。

使用 Fiddler 查看 WebSockets 流量

Fiddler 是一个流行的 HTTP 调试代理。最新版本对 WebSocket 协议提供了一些支持。您可以检查 WebSocket 握手中交换的标头。

所有 WebSocket 消息也会被记录下来。在下面的屏幕截图中,您可以看到“spiral”作为 UTF-8 文本消息发送到服务器并被回显。

结论

如果您想了解更多关于 WebSockets 的信息,可以观看 2011 年 9 月 Microsoft //Build/ 会议的这些环节:

如果您想了解如何使用 Microsoft 技术创建 WebSocket 服务,这些帖子是不错的入门资料:

立即开始使用 WebSockets 进行开发!

© . All rights reserved.