JavaScript之WebSocket技艺详解分分快三计划

作者:分分快三计划

> `WebSocket`协议可以实现前后端全双工通信,从而取代浪费资源的长轮询。在此协议的基础上,可以实现前后端数据、多端数据,真正的**实时响应**。在学习`WebSocket`的过程中,实现了一个简化版群聊,过程和代码详细记录在这篇文章中。 **本篇文章来自[董沅鑫的个人网站]( **查看更多知识,或者技术交流:请访问[`godbmw.com`]( ## 1 概述 ### 1.1 WebSocket 是什么? 1. 建立在 TCP 协议之上的网络通信协议 2. 全双工通信协议 3. 没有同源限制 4. 可以发送文本、二进制数据等 ### 1.2 为什么需要 WebSocket? 了解计算机网络协议的人,应该都知道:HTTP 协议是一种无状态的、无连接的、单向的应用层协议。它采用了请求/响应模型。通信请求只能由客户端发起,服务端对请求做出应答处理。 这种通信模型有一个弊端:HTTP 协议无法实现服务器主动向客户端发起消息。 因此,如果在客户端想实时监听服务器变化,必须使用 ajax 来进行轮询,效率低,浪费资源。 而 websocket 就可以使得**前后端进行全双工通信(两方都可以向对方进行数据推送),是真正的平等对话**。 ## 2 WebSocket 客户端 支持`HTML5`的浏览器支持 WebSocket 协议: ```javascript var ws = new WebSocket(url); // 创建一个websocket对象

socket.emit('anotherNews');

protocol

在构造函数中,protocol参数让服务端知道客户端使用的WebSocket协议。而WebSocket对象的这个属性就是指的最终服务端确定下来的协议名称,当服务端没有选择客户端提供的协议或者在连接握手结束之前,这个属性都是空的。

ws.onopen=function(){
console.log(ws.protocol);
}

``` ### 2.1 WebSocket 属性 | 属性 | 描述 | | ----------------- |

| | ws.readyState | 只读属性 readyState 表示连接状态,可以是以下值:0 - 表示连接尚未建立。1 - 表示连接已建立,可以进行通信。2 - 表示连接正在进行关闭。3 - 表示连接已经关闭或者连接不能打开。 | | ws.bufferedAmount | 只读属性 bufferedAmount 已被 send() 放入正在队列中等待传输,但是还没有发出的 UTF-8 文本字节数。 | ### 2.2 WebSocket 方法 | 属性 | 描述 | | ---------- | -------- | | ws.send() | 数据发送 | | ws.close() | 关闭连接 | ### 2.3 Websocket 事件 | 属性 | 描述 | | ------- | ------------ | | open | 连接建立触发 | | message | 通信时触发 | | error | 出错触发 | | close | 关闭连接触发 | ### 2.4 代码实现 假设我们在本地`8080`端口打开了websocket服务,那么,下面代码可以在浏览器中实现和这个服务的通信: ```html

``` ## 3 WebSocket 服务端 > 关于服务端实现,根据技术选型不同,可以选用不同的库和包。我这里使用的是`node`的`ws`库来websocket服务端。 在[阮一峰的博文]( 综上所述,`ws`库有以下优点: 1. 兼容性好,兼容浏览器原生API 2. 长期维护,效果稳定 3. 使用方便(往下看就知道了) ## 4 实现群聊 ### 4.1 群聊 服务端实现 首先,在命令行中,安装`ws`库: `npm install ws --save` 现在,利用`ws`来实现一个监听`8080`端口的websocket服务器,**讲解都在代码注释里,一目了然**: ```javascript const PORT = 8080; // 监听端口 const WebSocket = require("ws"); // 引入 ws 库 const wss = new WebSocket.Server({ port: PORT }); // 声明wss对象 /** * 向除了本身之外所有客户端发送消息,实现群聊功能 * @param {*} data 要发送的数据 * @param {*} ws 客户端连接对象 */ wss.broadcastToElse = function broadcast(data, ws) { wss.clients.forEach(function each(client) { if (client !== ws && client.readyState === WebSocket.OPEN) { client.send(data); } }); }; /* 客户端接入,触发 connection */ wss.on("connection", function connection(ws, req) { let ip = req.connection.remoteAddress; // 通过req对象可以获得客户端信息,比如:ip,headers等 /* 客户端发送消息,触发 message */ ws.on("message", function incoming(message) { ws.send(message); // 向客户端发送消息 wss.broadcastToElse(message, ws); // 向 其他的 客户端发送消息,实现群聊效果 }); }); ``` ### 4.2 群聊 客户端实现 为了方便编写,这里引入了`jquery`和`bootstrap`这两个库,只需要关注js代码即可。 ```html

群聊

发送

``` ### 4.3 群聊 效果展示 首先启动我们的服务端代码:`node server.js` 。其中,`server.js`是放置服务端代码的文件。 然后,我们打开2次编写的`html`代码,这相当于,打开2个客户端。来检测群聊功能。 ![效果图]() ## 5. 相关资料 - 概念解释: - - - `ws`文档: **本篇文章来自[董沅鑫的个人网站]( **查看更多知识,或者技术交流:请访问[`godbmw`](

var connection;
wsServer.on(‘request', function(req){

服务端响应:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat

WebSocket协议需要服务器支持,目前比较流行的实现是基于node.js的socket.io,更多的实现可参阅Wikipedia。至于浏览器端,目前主流浏览器都支持WebSocket协议(包括IE 10 ),仅有的例外是手机端的Opera Mini和Android Browser。

websocket事件

WebSocket API是纯事件驱动,通过监听事件可以处理到来的数据和改变的链接状态。客户端不需要为了更新数据而轮训服务器。服务端发送数据后,消息和事件会异步到达。WebSocket编程遵循一个异步编程模型,只需要对WebSocket对象增加回调函数就可以监听事件。你也可以使用addEventListener()方法来监听。

概述

定义

1、websocket是html5的的一个重要组件;
2、WebSocket 是一种基于ws协议的技术。使用它可以在客户端与服务器之间建立一段连续的、全双工的连接。它弥补了http不适合实时通信的重大缺陷。

分分快三计划 1

image.png

server.listen(1740, function() {

 console.log((new Date())   ' Server is listening on port 1740');

});

协议的握手过程

在客户端和服务端一开始握手的期间,http协议升级到WebSocket协议就建立了连接,底层都是TCP协议。一旦建立连接,通过WebSocket接口可以反复的发送消息。

为了建立WebSocket连接,客户端发送WebSocket握手请求,服务器返回一个WebSocket握手响应;

然后,开始与服务器建立连接(这里假定服务器就是本机的1740端口,需要使用ws协议)。

ws.close()

使用close方法来关闭连接,如果连接已经关闭,这方法将什么也不做。调用close方法之后,将不能发送数据。

发送数据和接收数据

特点

(1)服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。
(2)建立在 TCP 协议之上,服务器端的实现比较容易。
(3)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。
(4)数据格式比较轻量,性能开销小,通信高效。
(5)可以发送文本,也可以发送二进制数据。
(6)没有同源限制,客户端可以与任意服务器通信。
(7)协议标识符是ws(如果加密,则为wss),服务器网址就是 URL。

connection = req.accept(‘echo-protocol', req.origin); 
});

创建websocket实例

首先,我们需要通过调用WebSocket构造函数来创建一个WebSocket连接,构造函数会返回一个WebSocket实例,可以用来监听事件。这些事件会告诉你什么时候连接建立,什么时候消息到达,什么时候连接关闭了,以及什么时候发生了错误。WebSocket协议定义了两种URL方案,WS和WSS分别代表了客户端和服务端之间未加密和加密的通信。WS(WebSocket)类似于Http URL,而WSS(WebSocket Security)URL 表示连接是基于安全传输层(TLS/SSL)和https的连接是同样的安全机制。

WebSocket的构造函数需要一个URL参数和一个可选的协议参数(一个或者多个协议的名字),协议的参数例如XMPP(Extensible Messaging and Presence Protocol)、SOAP(Simple Object Access Protocol)或者自定义协议,服务端和客服端使用的协议必须一致,这样收发消息彼此才能理解。而URL参数需要以WS://或者WSS://开头,例如:ws://www.websocket.org,如果URL有语法错误,构造函数会抛出异常。

// WebSocket 对象作为一个构造函数,用于新建 WebSocket 实例
const ws = new WebSocket('ws://localhost:8282');

首先,客户端要检查浏览器是否支持WebSocket,使用的方法是查看window对象是否具有WebSocket属性。

bufferedAmount

有时候需要检查传输数据的大小,尤其是客户端传输大量数据的时候。虽然send()方法会马上执行,但数据并不是马上传输。浏览器会缓存应用流出的数据,你可以使用bufferedAmount属性检查已经进入队列但还未被传输的数据大小。

function wsError(event) { 
console.log(“Error: “   event.data); 
}
模拟聊天室

服务器端的WebSocket回应则是

客户端请求:
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com

上面代码表示,先建立并运行HTTP服务器。Socket.io的运行建立在HTTP服务器之上。

websocket方法

服务器端同样用“Connection: Upgrade”通知浏览器,需要改变协议。Sec-WebSocket-Accept是服务器在浏览器提供的Sec-WebSocket-Key字符串后面,添加“258EAFA5-E914-47DA-95CA-C5AB0DC85B11” 字符串,然后再取sha-1的hash值。浏览器将对这个值进行验证,以证明确实是目标服务器回应了webSocket请求。Sec-WebSocket-Location表示进行通信的WebSocket网址。

readyState 常量

返回实例对象的当前状态,共有四种

CONNECTING:值为0,表示正在连接。
OPEN:值为1,表示连接成功,可以通信了。
CLOSING:值为2,表示连接正在关闭。
CLOSED:值为3,表示连接已经关闭,或者打开连接失败。
function wsOpen (event) { 
console.log(‘Connected to: ‘   event.currentTarget.URL); 
}
Close

当连接关闭的时候回触发这个事件,对应onclose方法,连接关闭之后,服务端和客户端就不能再收发消息。

ws.onclose=function(e){
console.log('websocket closed', e);
console.log(e.code);
console.log(e.reason);
console.log(e.wasClean);
}

关闭事件有三个属性可以用来做异常处理和重获: wasClean,code和reason。wasClean是一个bool值,代表连接是否干净的关闭。 如果是响应服务端的close事件,这个值为true,如果是别的原因,比如因为是底层TCP连接关闭,wasClean为false。code和reason代表关闭连接时服务端发送的状态;

使用ws模块,部署一个简单的WebSocket服务器非常容易。

五、超级简单的demo

上面代码的回调函数接受一个参数req,表示request请求对象。然后,在回调函数内部,建立WebSocket连接connection。接着,就要对connection的message事件指定回调函数。

Open

一旦服务端响应WebSocket连接请求,就会触发open事件。响应的回调函数称为onopen。

ws.onopen=function(){
console.log('connection is opened!');
}
// 指定多个回调函数
ws.addEventListener('open', function (event) {
  console.log(‘connection is open!’);
});

open事件触发的时候,意味着协议握手结束,WebSocket已经准备好收发数据。如果你的应用收到open事件,就可以确定服务端已经处理了建立连接的请求,且同意和你的应用通信。

上面代码的回调函数wsMessage的参数为事件对象event,该对象的data属性包含了服务器返回的数据。

模拟股票

Socket.io是目前最流行的WebSocket实现,包括服务器和客户端两个部分。它不仅简化了接口,使得操作更容易,而且对于那些不支持WebSocket的浏览器,会自动降为Ajax连接,最大限度地保证了兼容性。它的目标是统一通信机制,使得所有浏览器和移动设备都可以进行实时通信。

ws.send()

一旦建立了连接,实例对象的send()方法可用于向服务器发送数据。(文本、blob对象、ArrayBuffer对象:类型化数组)

ws.send('message');

假设监听1740端口。

websocket API

connection.onerror = wsError;

Message

当消息被接受会触发消息事件,响应的回调函数叫做onmessage。接收的消息类型有文本信息、二进制数据(blob和ArrayBuffer两种类型)。

ws.onmessage = function(e) {
  const data = e.data;
}

建立连接和断开连接

Error

如果发生意外的失败会触发error事件,相应的函数称为onerror,错误会导致连接关闭。如果你收到一个错误事件,那么你很快会收到一个关闭事件,在关闭事件中也许会告诉你错误的原因。

ws.onerror = function(e){
console.log('websocket error', e);
handleErrors(e);
}

处理错误

websocket属性

WebSocket对象有三个属性,readyState,bufferedAmount和Protocol。

***建立连接和断开连接
发送数据和接收数据
处理错误

GET / HTTP/1.1
Connection: Upgrade
Upgrade: websocket
Host: example.com
Origin: null
Sec-WebSocket-Key: sN9cRrP/n9NdMgdcy2VJFQ==
Sec-WebSocket-Version: 13
上面的头信息显示,有一个HTTP头是Upgrade。HTTP1.1协议规定,Upgrade头信息表示将通信协议从HTTP/1.1转向该项所指定的协议。“Connection: Upgrade”就表示浏览器通知服务器,如果可以,就升级到webSocket协议。Origin用于验证浏览器域名是否在服务器许可的范围内。Sec-WebSocket-Key则是用于握手协议的密钥,是base64编码的16字节随机字符串。

建立连接以后的WebSocket实例对象(即上面代码中的connection),有一个readyState属性,表示目前的状态,可以取4个值:

如果接收的是二进制数据,需要将连接对象的格式设为blob或arraybuffer。

connection.onclose = wsClose;

connection.binaryType = 'arraybuffer';

connection.onmessage = function(e) {
 console.log(e.data.byteLength); // ArrayBuffer对象有byteLength属性
};

connection.send(message);
除了发送字符串,也可以使用 Blob 或 ArrayBuffer 对象发送二进制数据。

var http = require('http');

var server = http.createServer(function(request, response) {});

客户端

关闭WebSocket连接,会触发close事件。

Socket.io简介

var WebSocketServer = require('websocket').server;

var wsServer = new WebSocketServer({

 httpServer: server

});

var socket = io.connect('');

if(window.WebSocket != undefined) {

 var connection = new WebSocket('ws://localhost:1740');

}
function wsClose () { 
console.log(“Closed”); 
}

connection.close();
var WebSocketServer = require('ws').Server;
var wss = new WebSocketServer({ port: 8080 });

wss.on('connection', function connection(ws) {
 ws.on('message', function incoming(message) {
 console.log('received: %s', message);
 });

 ws.send('something');
});

服务器端

不管是服务器还是客户端,socket.io提供两个核心方法:emit方法用于发送消息,on方法用于监听对方发送的消息。

客户端收到服务器发送的数据,会触发message事件。可以通过定义message事件的回调函数,来处理服务端返回的数据。

connection.onopen = wsOpen;

WebSocket不使用HTTP协议,而是使用自己的协议。浏览器发出的WebSocket请求类似于下面的样子:

connection.onmessage = wsMessage;

如果出现错误,浏览器会触发WebSocket实例对象的error事件。

if(window.WebSocket != undefined) {

 // WebSocket代码

}
function wsMessage (event) { 
console.log(event.data); 
}

HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Accept: fFBooB7FAkLlXgRSz0BT3v4hq5s=
Sec-WebSocket-Origin: null
Sec-WebSocket-Location: ws://example.com/

服务器端需要单独部署处理WebSocket的代码。下面用node.js搭建一个服务器环境。

第二步,在根目录下建立app.js,并写入以下代码(假定使用了Express框架)。

HTTP协议是一种无状态协议,服务器端本身不具有识别客户端的能力,必须借助外部机制,比如session和cookie,才能与特定客户端保持对话。这多多少少带来一些不便,尤其在服务器端与客户端需要持续交换数据的场合(比如网络聊天),更是如此。为了解决这个问题,HTML5提出了浏览器的WebSocket API。

您可能感兴趣的文章:

  • 详解WebSocket spring示例demo(已使用sockJs库)
  • 基于html5和nodejs相结合实现websocket即使通讯
  • 浅析nodejs实现Websocket的数据接收与发送
  • Python通过websocket与js客户端通信示例分析
  • Javascript WebSocket使用实例介绍(简明入门教程)
  • JS实现websocket长轮询实时消息提示的效果

浏览器端对WebSocket协议的处理,无非就是三件事:

WebSocket协议完全可以取代Ajax方法,用来向服务器端发送文本和二进制数据,而且还没有“同域限制”。

由于本例假定WebSocket主机与客户端是同一台机器,所以connect方法的参数是

0: 正在连接
1: 连接成功
2: 正在关闭
3: 连接关闭
握手协议成功以后,readyState就从0变为1,并触发open事件,这时就可以向服务器发送信息了。我们可以指定open事件的回调函数。

// 使用ArrayBuffer发送canvas图像数据

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);
// 使用Blob发送文件 
var file = document.querySelector(‘input[type=”file”]').files[0]; 
connection.send(file);

最后,用emit方法向服务器端发送信号,触发服务器端的anotherNews事件。

连接建立后,客户端通过send方法向服务器端发送数据。

connection.on('close', function(reasonCode, description) {

 console.log(connection.remoteAddress   ' disconnected.');

});
wsServer.on(‘request', function(r){

 connection = req.accept(‘echo-protocol', req.origin);



connection.on('message', function(message) {
 var msgString = message.utf8Data;
 connection.sendUTF(msgString);
});
});

请注意,WebSocket协议用ws表示。此外,还有wss协议,表示加密的WebSocket协议,对应HTTPs协议。
完成握手以后,WebSocket协议就在TCP协议之上,开始传送数据。

上面代码的io.sockets.on方法指定connection事件(WebSocket连接建立)的回调函数。在回调函数中,用emit方法向客户端发送数据,触发客户端的news事件。然后,再用on方法指定服务器端anotherNews事件的回调函数。

请注意,emit方法可以取代Ajax请求,而on方法指定的回调函数,也等同于Ajax的回调函数。
第四步,在服务器端的app.js,加入以下代码。

WebSocket的主要作用是,允许服务器端与客户端进行全双工(full-duplex)的通信。举例来说,HTTP协议有点像发电子邮件,发出后必须等待对方回信;WebSocket则是像打电话,服务器端和客户端可以同时向对方发送数据,它们之间存着一条持续打开的数据通道。

<script src="/socket.io/socket.io.js"></script>

第一步,在服务器端的项目根目录下,安装socket.io模块。

然后,在客户端脚本中,建立WebSocket连接。

io.sockets.on('connection', function (socket) {
 socket.emit('news', { hello: 'world' });
 socket.on('anotherNews', function (data) {
 console.log(data);
 });
});
socket.on('news', function (data){
 console.log(data);
});

$ npm install socket.io

接着启动WebSocket服务器。这需要加载websocket库,如果没有安装,可以先使用npm命令安装。

第三步,将Socket.io插入客户端网页。

WebSocket服务器建立request事件的回调函数。

var app = require('express')();
var server = require('http').createServer(app);
var io = require('socket.io').listen(server);

server.listen(80);

app.get('/', function (req, res) {
 res.sendfile(__dirname   '/index.html');
});

最后,监听用户的disconnect事件。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

本文由分分快三计划发布,转载请注明来源

关键词: 分分快三计划 日记本