JavaScript之WebSocket技术详解

概述

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

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

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

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

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回应则是

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

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

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

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

客户端

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

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

建立连接和断开连接

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

if(window.WebSocket != undefined) {

 // WebSocket代码

}

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

if(window.WebSocket != undefined) {

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

}

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

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

connection.onopen = wsOpen;

function wsOpen (event) {
console.log(‘Connected to: ‘ + event.currentTarget.URL);
}

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

connection.onclose = wsClose;

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

connection.close();

发送数据和接收数据

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

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

// 使用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);

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

connection.onmessage = wsMessage;

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

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

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

connection.binaryType = 'arraybuffer';

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

处理错误

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

connection.onerror = wsError;

function wsError(event) {
console.log(“Error: “ + event.data);
}

服务器端

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

var http = require('http');

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

假设监听1740端口。

server.listen(1740, function() {

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

});

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

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

var wsServer = new WebSocketServer({

 httpServer: server

});

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

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

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

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

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

 connection = req.accept(‘echo-protocol', req.origin);
<span class="nx">connection</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">'message'</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">message</span><span class="p">)</span> <span class="p">{</span>
 <span class="kd">var</span> <span class="nx">msgString</span> <span class="o">=</span> <span class="nx">message</span><span class="p">.</span><span class="nx">utf8Data</span><span class="p">;</span>
 <span class="nx">connection</span><span class="p">.</span><span class="nx">sendUTF</span><span class="p">(</span><span class="nx">msgString</span><span class="p">);</span>
<span class="p">});</span>
});

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

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

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

});

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

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简介

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

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

$ npm install socket.io

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

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');
});

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

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

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

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

var socket = io.connect('http://localhost:80');

由于本例假定WebSocket主机与客户端是同一台机器,所以connect方法的参数是http://localhost。接着,指定news事件(即服务器端发送news)的回调函数。

socket.on('news', function (data){
 console.log(data);
});

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

socket.emit('anotherNews');

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

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

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

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

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

(0)

相关推荐

  • 详解WebSocket+spring示例demo(已使用sockJs库)

    1.简介 作为下一代的Web标准,HTML5拥有许多引人注目的新特性,如 Canvas.本地存储.多媒体编程接口.WebSocket等等.这其中有"Web的 TCP"之称的 WebSocket格外吸引开发人员的注意.WebSocket的出现使得浏览器提供对 Socket的支持成为可能,从而在浏览器和服务器之间提供了一个基于TCP连接的双向通道.Web开发人员可以非常方便地使用WebSocket构建实时 web 应用,开发人员的手中从此又多了一柄神兵利器. Web 应用的信息交互过程通常

  • Python通过websocket与js客户端通信示例分析

    具体的 websocket 介绍可见 http://zh.wikipedia.org/wiki/WebSocket 这里,介绍如何使用 Python 与前端 js 进行通信. websocket 使用 HTTP 协议完成握手之后,不通过 HTTP 直接进行 websocket 通信. 于是,使用 websocket 大致两个步骤:使用 HTTP 握手,通信. js 处理 websocket 要使用 ws 模块: Python 处理则使用 socket 模块建立 TCP 连接即可,比一般的 soc

  • 基于html5和nodejs相结合实现websocket即使通讯

    最近都在学习HTML5,做canvas游戏之类的,发现HTML5中除了canvas这个强大的工具外,还有WebSocket也很值得注意.可以用来做双屏互动游戏,何为双屏互动游戏?就是通过移动端设备来控制PC端网页游戏.这样的话就要用到实时通讯了,而WebSocket无疑是最合适的.WebSocket相较于HTTP来说,有很多的优点,主要表现在WebSocket只建立一个TCP连接,可以主动推送数据到客户端,而且还有更轻量级的协议头,减少数据传送量.所以WebSocket暂时来说是实时通讯的最佳协

  • 浅析nodejs实现Websocket的数据接收与发送

    WebSocket是HTML5开始提供的一种浏览器与服务器间进行全双工通讯的网络技术.在WebSocket API中,浏览器和服务器只需要要做一个握手(handshaking)的动作,然后,浏览器和服务器之间就形成了一条快速通道.两者之间就直接可以数据互相传送. WebSocket是一个通信的协议,分为服务器和客户端.服务器放在后台,保持与客户端的长连接,完成双方通信的任务.客户端一般都是实现在支持HTML5浏览器核心中,通过提供JavascriptAPI使用网页可以建立websocket连接.

  • JS实现websocket长轮询实时消息提示的效果

    效果图如下: 参考代码如下: jsp代码: <%@ page contentType="text/html;charset=UTF-8" language="java"%> <div class="page-header navbar navbar-fixed-top"> <div class="page-header-inner"> <div class="page-log

  • Javascript WebSocket使用实例介绍(简明入门教程)

    一旦你了解了网络套接字与WEB服务器的连接,你将可以从浏览器发送数据到服务器并且可以接收由服务器返回的响应数据. 以下是创建一个新的WebSocket对象的API: 复制代码 代码如下: var Socket = new WebSocket(url, [protocal] ); 这里第一个参数是指要连接的URL,第二个参数是可选的,如果需要的话,则是指定一个的服务器支持的协议. WEB Socket属性: 属性 说明 Socket.readyState readyState的代表的ReadOnl

  • JavaScript之WebSocket技术详解

    概述 HTTP协议是一种无状态协议,服务器端本身不具有识别客户端的能力,必须借助外部机制,比如session和cookie,才能与特定客户端保持对话.这多多少少带来一些不便,尤其在服务器端与客户端需要持续交换数据的场合(比如网络聊天),更是如此.为了解决这个问题,HTML5提出了浏览器的WebSocket API. WebSocket的主要作用是,允许服务器端与客户端进行全双工(full-duplex)的通信.举例来说,HTTP协议有点像发电子邮件,发出后必须等待对方回信:WebSocket则是

  • javascript中indexOf技术详解

    JavaScript提供了几种技术,来在字符串中搜索一个单词.数字或其他的一串字符.搜索可能很方便,例如,如果你想要知道访问者使用哪种Web浏览器来浏览你的站点.每个Web浏览器在一个字符串中标识关于自己的信息,该字符串包含了很多不同的统计数据.可以通过在一个Web页面中添加下面这段JavaScript,并且在Web浏览器预览,从而看到这个字符串: <script> alert(navigator.userAgent): </script> Navigator是一个Web浏览器对象

  • JavaScript之cookie技术详解

    运用JS设置cookie.读取cookie.删除cookie JavaScript是运行在客户端的脚本,因此一般是不能够设置Session的,因为Session是运行在服务器端的. 而cookie是运行在客户端的,所以可以用JS来设置cookie. 假设有这样一种情况,在某个用例流程中,由A页面跳至B页面,若在A页面中采用JS用变量temp保存了某一变量的值,在B页面的时候,同样需要使用JS来引用temp的变量值,对于JS中的全局变量或者静态变量的生命周期是有限的,当发生页面跳转或者页面关闭的时

  • 基于JavaScript表单脚本(详解)

    什么是表单? 一个表单有三个基本组成部分: 表单标签:这里面包含了处理表单数据所用CGI程序的URL以及数据提交到服务器的方法. 表单域:包含了文本框.密码框.隐藏域.多行文本框.复选框.单选框.下拉选择框和文件上传框等. 表单按钮:包括提交按钮.复位按钮和一般按钮:用于将数据传送到服务器上的CGI脚本或者取消输入,还可以用表单按钮来控制其他定义了处理脚本的处理工作. JavaScript与表单间的关系:JS最初的应用就是用于分担服务器处理表单的责任,打破依赖服务器的局面,尽管目前web和jav

  • javascript异常处理实现原理详解

    这篇文章主要介绍了javascript异常处理实现原理详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一.什么是例外处理 当 JavaScript程序在运行中发生了诸如数组索引越界.类型不匹配或者语法错误时,JavaScript解释器就会引发例外处理. ECMAScript定义了六种类型的错误,除此之外,我们可以使用Error对象和throw语句来创建并引发自定义的例外处理信息. 通过运用例外处理技术,我们可以实现用结构化的方式来响应错误事

  • javascript中Promise使用详解

    目录 一.首先,要知道为什么要用Promise语法? 二.接着,来了解一下回调地狱(Callback Hell) 三.最后,也是本章的重头戏,Promise的基本使用 (一) resolve函数 (二) rejected函数 (三)Promise的API 1. then 2. catch 3. finally 4. Promise.all 5. Promise.race 四.最后 前言: 做过前端开发的都知道,JavaScript是单线程语言,浏览器只分配给JS一个主线程,用来执行任务,但是每次

  • JavaScript数据结构链表知识详解

    最近在看<javascript数据结构和算法>这本书,补一下数据结构和算法部分的知识,觉得自己这块是短板. 链表:存储有序的元素集合,但不同于数组,链表中的元素在内存中不是连续放置的.每个元素由一个存储元素本身的节点和一个指向下一个元素的引用(也称指针或链接)组成. 好处:可以添加或移除任意项,它会按需扩容,且不需要移动其他元素. 与数组的区别: 数组:可以直接访问任何位置的任何元素: 链表:想要访问链表中的一个元素,需要从起点(表头)开始迭代列表直到找到所需的元素. 做点小笔记. funct

  • JavaScript里 ==与===区别详解

    1.对于string,number等基础类型,==和===是有区别的 1)不同类型间比较,==之比较"转化成同一类型后的值"看"值"是否相等,===如果类型不同,其结果就是不等 2)同类型比较,直接进行"值"比较,两者结果一样 2.对于Array,Object等高级类型,==和===是没有区别的 进行"指针地址"比较 3.基础类型与高级类型,==和===是有区别的 1)对于==,将高级转化为基础类型,进行"值&quo

  • JavaScript String 对象常用方法详解

    字符串是不可变的.字符串方法,不会改变原有字符串的内容,而是返回一个新字符串. charAt():返回在指定位置的字符. concat():连接两个字符串文本,并返回一个新的字符串. indexOf(): indexOf() 方法返回指定值在字符串对象中首次出现的位置. match(): 使用正则表达式与字符串相比较. replace(): 被用来在正则表达式和字符串直接比较,然后用新的子串来替换被匹配的子串. slice(): 摘取一个字符串区域,返回一个新的字符串. split(): 通过分

  • java多线程编程技术详解和实例代码

     java多线程编程技术详解和实例代码 1.   Java和他的API都可以使用并发. 可以指定程序包含不同的执行线程,每个线程都具有自己的方法调用堆栈和程序计数器,使得线程在与其他线程并发地执行能够共享程序范围内的资源,比如共享内存,这种能力被称为多线程编程(multithreading),在核心的C和C++语言中并不具备这种能力,尽管他们影响了JAVA的设计. 2.   线程的生命周期 新线程的生命周期从"新生"状态开始.程序启动线程前,线程一直是"新生"状态:

随机推荐