WebSocket 是一种在单个TCP连接上进行全双工通信的协议。WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。
起初,浏览器是request——response模式,只有当用户向浏览器发送了请求,浏览器才能将数据发送给用户,这种模式下并不支持浏览器主动向用户发送数据,像如今的热门推送,在当时都是无法实现的,当时能做到的最多就是以静态页面的形式推送信息,根本无法和今天的动态获取热门信息相比。为了实现web 页面和服务器之间的实时交互通信,当时的开发人员滥用 XMLHttpRequest 来实现这一功能。最出名的就是长轮询,也就是让 HTTP 连接保持打开状态意味着只要连接保持打开状态,服务器就可以继续持续响应数据,以此来实现服务器与客户端的双向通信。
长轮询是对原有的询问技术的一种更有效的利用方式,但是向服务器发送重复请求会浪费资源,这需要为每个新传入的请求建立连接,并解析请求的 HTTP 头部,执行对新数据的查询,并且必须生成和交付响应,但是交付的响应往往是没有新数据的。然后又必须关闭连接并清除所有资源。这就对浏览器的性能造成了很大的浪费。直至2008年Websocket被首次提出,时至今日,Websocket已被所有的主流浏览器所支持,前景良好。
下面是server.js里的代码,也就是我用node写的简易服务器的代码。由于只是一个练习的小测试,因此并没有什么详细的处理数据的代码,其中的handleOpen(),handleClose(),handleError(),handleConnection(ws)分别是当websocket服务打开,关闭,出错,链接上的时候的相关函数,我只写了打印一句话的代码。handleMessage()是将消息发送给每一个对象的函数
- const Ws = require('ws');
- ;((Ws) => {
- const server = new Ws.Server({ port: 8080 });
- const init = () =>{
- bindEvent();
- }
- function bindEvent(){
- server.on('open', handleOpen);
- server.on('close', handleClose);
- server.on('error', handleError);
- server.on('connection', handleConnection);
- }
- function handleOpen(){
- console.log("Websocket open");
- }
- function handleClose(){
- console.log("Websocket close");
- }
- function handleError(){
- console.log("Websocket error");
- }
- function handleConnection(ws){
- console.log("Websocket connected");
- ws.on('message',handleMessage);
- }
- function handleMessage(msg){
- server.clients.forEach(function(c){
- c.send(msg.toString());
- })
- }
- init();
- })(Ws);
下面就是我在js中写的代码了,也就是前端使用websocket服务的时候需要在html使用的js中写的代码。在bindEvent函数中写下监听事件,来实现对应功能的响应。例如当发送按钮按下的时候,执行handleSendBtnClick函数,判断信息是否为空,为空则为误触,否则使用ws.send将信息传递给服务器。handleOpen函数则是用来判断函数名是否存在的,若不存在,则代表没有登录,跳转到登录页面。由于是练习用的,我直接将登录后的用户名存在了本地,在接受信息的时候,也只是简单的根据用户名判断是否为本人,再来使用不同的渲染方式。
- ;((doc,WebSocket,storage,location) =>{
- const oList = doc.querySelector(".room")
- const oMsg = doc.querySelector(".write")
- const oSendBtn = doc.querySelector(".send")
- const ws = new WebSocket('ws://localhost:8080')
- let username = '';
-
- const init = () => {
- bindEvent();
- }
-
- function bindEvent(){
- oSendBtn.addEventListener('click',handleSendBtnClick,false);
- ws.addEventListener("open",handleOpen,false);
- ws.addEventListener("close",handleClose,false);
- ws.addEventListener("error",handleError,false);
- ws.addEventListener("message",handleMessage,false);
- }
-
- function handleSendBtnClick(){
- const msg = oMsg.innerHTML;
- if(!msg.trim().length){
- return;
- }
- ws.send(
- JSON.stringify({
- user:username,
- dateTime: new Date().getTime(),
- message:msg
- })
- );
- oMsg.innerHTML = ''
- }
- function handleOpen(e){
- console.log("Websocket open",e);
- username = Localstorage.getItem("username");
- if(!username){
- location.href = 'entry.html';
- return;
- }
- }
- function handleClose(e){
- console.log("Websocket close",e);
- }
- function handleError(e){
- console.log("Websocket error",e);
- }
- function handleMessage(e){
- console.log("Websocket message");
- const msgData = typeof e.data =='string' ? JSON.parse(e.data) :e.data;
- console.log(msgData)
- oList.appendChild(crerateMsg(msgData))
- }
-
- function crerateMsg(data){
- const { user , dateTime , message } = data;
- const oItem = doc.createElement('div');
- if(user == storage.getItem("username")){
- oItem.innerHTML = `
- <div class="mine">
- <div class="usermessage">
- <img class="headphoto" src="./img/myheader.jpg">
- <div class="usernamediv">${ user }</div>
- </div>
- <div class="messagediv"><span class="message">${ message }</span></div>
- </div>
- `;
- }else{
- oItem.innerHTML = `
- <div class="others">
- <div class="usermessage">
- <img class="headphoto" src="./img/headerfive.jpg">
- <div class="othernamediv">${ user }</div>
- </div>
- <div class="messagediv"><span class="othermessage">${ message }</span></div>
- </div>
- `;
- }
- return oItem
- }
-
- init();
- })(document,WebSocket,localStorage,location);
由于Websocket下客户端和服务器之间的联系是长时间存在的,有时会就会存在用户长时间未进行操作,也就是客户端和服务器之间长时间不存在通信,此时服务器端是很难判断是用户未进行操作还是连接意外中断,因此就产生了Websocket心跳机制和重连机制。心跳机制是客户端每隔一段时间就会向服务器发送一个数据包,来让服务器得知连接无恙,而服务器在获取到数据包之后,也会给客户端发送一个数据包,让客户端得知连接无恙,倘若出现问题,则代表连接出现问题,进行重连。