WebSocket - 与服务器通信



Web 大部分构建在 HTTP 的请求/响应模式之上。客户端加载网页,然后在用户点击下一个页面之前没有任何事情发生。大约在 2005 年,AJAX 开始让 Web 感觉更加动态。但是,所有 HTTP 通信都由客户端控制,这需要用户交互或定期轮询才能从服务器加载新数据。

能够让服务器在知道新数据可用时立即将数据发送到客户端的技术已经存在相当一段时间了。它们被称为“推送”“Comet”

使用长轮询,客户端打开与服务器的 HTTP 连接,并保持连接打开直到发送响应。每当服务器实际拥有新数据时,它就会发送响应。长轮询和其他技术运行良好。但是,所有这些都存在一个共同的问题,它们承载着 HTTP 的开销,这使得它们不适合低延迟应用程序。例如,浏览器中的多人射击游戏或任何其他具有实时组件的在线游戏。

将 Socket 带到 Web

WebSocket 规范定义了一个 API,用于在 Web 浏览器和服务器之间建立“套接字”连接。通俗地说,客户端和服务器之间存在一个持久连接,并且双方都可以随时开始发送数据。

可以使用构造函数简单地打开 WebSocket 连接:

var connection = new WebSocket('ws://html5rocks.websocket.org/echo', ['soap', 'xmpp']);

ws 是 WebSocket 连接的新 URL 方案。还有wss,用于安全 WebSocket 连接,就像https 用于安全 HTTP 连接一样。

立即将一些事件处理程序附加到连接,使您能够知道连接何时打开、接收传入消息或出现错误。

第二个参数接受可选的子协议。它可以是字符串或字符串数组。每个字符串都应表示一个子协议名称,服务器仅接受数组中传递的子协议之一。可以通过访问 WebSocket 对象的 protocol 属性来确定已接受的子协议

// When the connection is open, send some data to the server
connection.onopen = function () {
   connection.send('Ping'); // Send the message 'Ping' to the server
};

// Log errors
connection.onerror = function (error) {
   console.log('WebSocket Error ' + error);
};

// Log messages from the server
connection.onmessage = function (e) {
   console.log('Server: ' + e.data);
};

与服务器通信

一旦我们与服务器建立连接(当 open 事件触发时),我们就可以开始使用连接对象上的 send(您的消息)方法向服务器发送数据。它过去仅支持字符串,但在最新的规范中,它现在也可以发送二进制消息。要发送二进制数据,使用 Blob 或 ArrayBuffer 对象。

// Sending String
connection.send('your message');

// Sending canvas ImageData as ArrayBuffer
var img = canvas_context.getImageData(0, 0, 400, 320);
var binary = new Uint8Array(img.data.length);

for (var i = 0; i < img.data.length; i++) {
   binary[i] = img.data[i];
}

connection.send(binary.buffer);

// Sending file as Blob
var file = document.querySelector('input[type = "file"]').files[0];
connection.send(file);

同样,服务器也可能随时向我们发送消息。每当发生这种情况时,onmessage 回调就会触发。回调接收一个事件对象,实际消息可以通过data属性访问。

WebSocket 在最新的规范中也可以接收二进制消息。二进制帧可以以 Blob 或 ArrayBuffer 格式接收。要指定接收到的二进制的格式,将 WebSocket 对象的 binaryType 属性设置为“blob”或“arraybuffer”。默认格式为“blob”。

// Setting binaryType to accept received binary as either 'blob' or 'arraybuffer'
connection.binaryType = 'arraybuffer';
connection.onmessage = function(e) {
   console.log(e.data.byteLength); // ArrayBuffer object if binary
};

WebSocket 的另一个新增功能是扩展。使用扩展,可以发送压缩、多路复用等帧。

// Determining accepted extensions
console.log(connection.extensions);

跨域通信

作为一种现代协议,跨域通信直接集成到 WebSocket 中。WebSocket 允许任何域上的各方之间进行通信。服务器决定是将其服务提供给所有客户端,还是仅提供给驻留在已定义域集中的客户端。

代理服务器

每种新技术都会带来一组新问题。在 WebSocket 的情况下,它与代理服务器的兼容性,代理服务器在大多数公司网络中充当 HTTP 连接的中介。WebSocket 协议使用 HTTP 升级系统(通常用于 HTTP/SSL)将 HTTP 连接“升级”到 WebSocket 连接。一些代理服务器不喜欢这样做,并且会断开连接。因此,即使给定客户端使用 WebSocket 协议,也可能无法建立连接。这使得下一节更加重要 :)

服务器端

使用 WebSocket 为服务器端应用程序创建了一种全新的使用模式。虽然 LAMP 等传统服务器堆栈是围绕 HTTP 请求/响应周期设计的,但它们通常无法很好地处理大量打开的 WebSocket 连接。同时保持大量连接打开需要一种能够以低性能成本接收高并发性的架构。

广告