HTML5新特性之WebSocket
在Web应用越来越复杂的今天,消息推送已经成为一个非常重要的功能了,有了消息推送,Web页面就能够及时的接收到来自服务端的消息,为用户展现 最好的交互体验。过去我们在实现Web页面的消息推送时,一般都是由页面发起请求,以轮询的方式向服务器获取数据,实现起来极为不便,业务逻辑也相对较为 复杂。
为了解决这个问题,进而实现真正意义上的消息推送,HTML5定义了一套新的规范,这就是WebSocket。下面我们就来介绍一下WebSocket这个新特性。
WebSocket是一种用于在服务器和客户端之间实现高效的双向通信的机制,通过WebSocket,能够实现在一个HTTP连接上自由地双向收发消息。
在通过WebSocket进行双向通信时,首先我们需要和服务器建立连接,这需要由客户端通过HTTP方式发送,服务器将会确认连接对象的源和协议,并发送连接许可响应,在客户端收到响应之后,一个WebSocket通信就正式建立起来了。
1、什么是WebSocket
WebSocket 是一种自然的全双工、双向、单套接字连接。使用WebSocket,你的HTTP 请求变成打开WebSocket 连接(WebSocket 或者WebSocket over TLS(TransportLayer Security,传输层安全性,原称“SSL”))的单一请求,并且重用从客户端到服务器以及服务器到客户端的同一连接。WebSocket 减少了延迟,因为一旦建立起WebSocket 连接,服务器可以在消息可用时发送它们。例如,和轮询不同,WebSocket只发出一个请求。服务器不需要等待来自客户端的请求。相似地,客户端可以在 任何时候向服务器发送消息。相比轮询不管是否有可用消息,每隔一段时间都发送一个请求,单一请求大大减少了延迟。
2、WebSocket API
WebSocket API 使你可以通过Web,在客户端应用程序和服务器端进程之间建立全双工的双向通信。WebSocket 接口规定了可用于客户端的方法以及客户端与网络的交互方式。首先,你要调用WebSocket 构造函数(constructor),创建一个WebSocket 连接。构造函数返回WebSocket 对象实例。你可以监听该对象上的事件,这些事件告诉你何时连接打开,何时消息到达,何时连接关闭以及何时发生错误。你可以与WebSocket 对象交互,发送消息或者关闭连接。下面来研究WebSocket API 的各个方面。
3、WebSocket 构造函数
为 了建立到服务器的WebSocket 连接,使用WebSocket 接口,通过指向一个代表所要连接端点的URL,实例化一个WebSocket对象。WebSocket 协议定义了两种URL 方案(URL scheme)—ws 和wss,分别用于客户端和服务器之间的非加密与加密流量。ws(WebSocket) 方案与HTTP URI 方案类似。wss(WebSocketSecure,WebSocket 安全)URI 方案表示使用传输层安全性(TLS,也叫SSL)的WebSocket 连接,使用HTTPS 采用的安全机制来保证HTTP 连接的安全。WebSocket 构造函数有一个必需的参数URL(指向连接目标的URL)和一个可选参数protocols(为了建立连接,服务器必须在其响应中包含的一个或一组协议名 称)。在protocols 参数中可以使用的协议包括XMPP(eXtensible Messaging and PresenceProtocol, 可扩展消息处理现场协议)、SOAP(Simple ObjectAccess Protocol,简单对象访问协议)或者自定义协议。
webSocket:
(1) 服务端:
创建服务:
1.WebSocketServer=require('ws').Server 返回 socket类
2.sktServer=new WebSocketServer({port:9000}) 实例化一个socket服务对象
收消息(读socket):
sktServer.on('connection',(clientSocket)=>{})检测连接
clientSocket == 客户端socket对象
clientSocket.on('message',()=>{mess}) 接受当前客户端消息
mess == 客户端过来的消息
clientSocket.on('close',()=>{}) 客户端下线
写消息(写socket):
clientSocket.send(消息)
(2) 客户端:
链接服务:
1. clientSocket=new WebSocket('ws://127.0.0.1:9000')
创建socket|链接服务|在没有成功的情况会频繁链接服务
事件:
clientSocket.onopen=function(){} 链接成功,就只会调用一次
收消息(读socket):
clientSocket.onmessage=function(ev){ev.data==接受到的消息}
clientSocket.onerror=function(){} 服务连接错误
clientSocket.onclose=function(){} 服务端关闭
写消息(写socket):
clientSocket.send('上线了')
4. 那么我们如何在客户端向服务器端发送请求呢?这时我们需要实例化一个WebSocket,代码如下所示:
var socket = new WebSocket('ws://www.websocket-testing.com:9000/server', 'subprotocol');
上面构造函数中的第一个参数是将要进行连接的WebScoket服务器的URL,第二个参数则是子协议名。需要注意的是,URL中我们可以选择 “ws://”或“wss://”这两种协议,这两种协议分别默认使用80和443端口来通信,如果使用后者,是可以用TLS对通信加密的。第二个参数也 可以是一个数组,以指定多个子协议名。
在执行构造函数之后,通信内部就会建立连接,一旦连接建立成功,WebSocket实例的open事件就会被触发:
socket.onopen = function(e) { 2 console.log('websocket connection has established'); 3 }
在连接建立成功之后,就可以进行消息收发了,这时我们可以调用send方法将消息发送到服务器,然后通过捕获message事件接收来自服务器的消息:
//send message to websocket server socket.send('hello, server'); //receive message from websocket server socket.onmessage = function(e){ //obtain the message from server var message = e.data; //do something }
在上面的代码中,我们发送了一个字符串类型的消息到服务器端,然后接收来自服务器端消息时,我们可以从event的data属性中取得。目前 WebSocket可以收发消息的类型有String、Blob和ArrayBuffer,后面两个主要用于收发二进制数据的,日常开发中我们使用 String类型就足够了,如果我们想要发送自定义对象,只需将其转换成JSON字符串后发送,如果客户端和服务端是以JSON形式通信,客户端收到消息 后在将其转换为JavaScript对象即可。
在通信结束后,客户端可以调用close方法主动断开与服务器端的连接,如果连接断开,close事件就会被触发,我们可以捕获此事件,做进一步的操作处理:
//cut off the connection socket.close(); socket.onclose = function(e){ //do something }
有些时候,因为网络问题或者服务器宕机的原因,客户端连接被切断,此时我们可以在捕获close事件后,试图重新建立连接,如下面代码所示:
socket.onclose = function() { setTimeout(function() { //reconnect operation }, 100000); }
如果服务器宕机之后,有新的客户端试图连接,这种情况下会导致连接失败,error就会被触发,我们可以捕获error事件,做相应的处理操作:
socket.onerror = function() { console.log('socket error occurred'); };
需要注意的是,连接失败后,error和close会相继触发,所以实际开发中要避免处理操作的重叠。
接下来,为了能够更好的展示WebSocket的交互过程,我们会建立起从客户端到服务端的一个简易的实时在线聊天程序。
服务端
要建立起聊天程序,首先我们需要搭建服务端环境,使其支持WebSocket通信,目前大多服务器端编程语言都有自己相对应的库,大家可以根据自己的熟悉程度去选择,在这里我们选用Node.js搭建一个简易的WebSocket服务。
首先进入项目目录文件下 进行项目初始化,生成package.json文件进行项目管理:
npm init
Node.js平台上有很多功能强大的WebSocket库,感兴趣的同学们都可以去了解一下,这里我们为了阐述基本用法,就选取一个叫ws的简易的库,使用npm命令安装即可:
npm install ws -D
如果对这个库不太熟悉的话,可以去github上看一下其使用说明:https://github.com/websockets/ws。 那么接下来我们就要创建一个简单的服务了,安装完ws库之后,只需在node_modules同级目录下创建一个websocket-server.js文件和客户端websocketClient.html文件即可;如图:
下面是websocket-server.js中的一段简易的代码:
1 const WebSocketServer=require('ws').Server;//引入模块 2 const server=new WebSocketServer({port:9000});//创建socket 3 4 const clientMap=new Object();//{用户1:client,用户2:client}//管理用户 5 let i=0; 6 7 server.on('connection',(client)=>{//检测连接 8 console.log(client.toString()+'连接我了'); 9 client.name= '用户'+ ++i; 10 clientMap[client.name]=client; 11 12 client.on('message',(message)=>{//读 13 // console.log(message); 14 console.log(client.name+'上线了'); 15 // client.send('你来了?')//写socket 16 broadcast(message,client);//批量写socket 17 }); 18 client.on('close',()=>{ 19 delete clientMap[client.name]; 20 broadcast('下线了',client) 21 }); 22 }); 23 24 let broadcast=function(message,client){ 25 for(let key in clientMap){ 26 clientMap[key].send(`${client.name}说: ${message}`); 27 } 28 };
为了方便我把客户端的HTML代码和javascript脚本写在一个文件中:
<head> <meta charset="UTF-8"> <title>666</title> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"> <meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-status-bar-style" content="black"> <style> </style> <script> window.onload = function () { const client=new WebSocket('ws://127.0.0.1:9000');//创建socket client.onopen=function(){ // alert('客户端的socket开启并连接服务端成功') client.send('上线了')//写socket sayinput.disabled=false; } client.onmessage=function(ev){//读取socket chatroom.innerHTML+=ev.data+'<br>'; }; client.onerror=function(){ chatroom.innerHTML+='服务连接错误'+'<br>'; }; client.onclose=function(){ chatroom.innerHTML+='服务关闭'+'<br>'; sayinput.disabled=true; }; sendbutton.onclick=function(){ client.send(sayinput.value);//写socket }; }; </script> </head> <body> <h1>WebSocket</h1> <div id="chatroom" style="width:400px;height:300px;overflow:auto;border:1px solid blue"></div> <input type="text" name="sayinput" id="sayinput" value=""> <input type="button" name="send" id="sendbutton" value="发送"> </body> </html>
最后实现客户端和服务端信息双向传递

参考:http://blog.csdn.net/liuhe688/article/details/50496780
https://www.cnblogs.com/shizhouyu/p/4975409.html

浙公网安备 33010602011771号