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

 

posted @ 2017-12-25 18:15  孙氏楼  阅读(530)  评论(0)    收藏  举报