1.什么是Websocket
WebSocket 是一种在单个TCP连接上进行全双工通信的协议。WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。
- Tcp,英文全称为Transmission Control Protocol,是一种面向连接的、可靠的、基于字节流的传输层通信协议。通俗一点理解就是在网络世界里的一种信息传递方式,像是现实生活中的写信等等,是电子设备传递信息的一种方式。
- 全双工,通讯传输的一种方式。除了全双工外,还有半双工和单工。单工指数据只能单向传输,半双工指数据可以双向传输,但是同一时刻只能有一方传输数据,全双工就是指双方可以同时传数据。通俗一点可以理解为单工是单向车道,半双工是潮汐车道,全双工就是双向车道。
2.Websocket背景
起初,浏览器是request——response模式,只有当用户向浏览器发送了请求,浏览器才能将数据发送给用户,这种模式下并不支持浏览器主动向用户发送数据,像如今的热门推送,在当时都是无法实现的,当时能做到的最多就是以静态页面的形式推送信息,根本无法和今天的动态获取热门信息相比。为了实现web 页面和服务器之间的实时交互通信,当时的开发人员滥用 XMLHttpRequest 来实现这一功能。最出名的就是长轮询,也就是让 HTTP 连接保持打开状态意味着只要连接保持打开状态,服务器就可以继续持续响应数据,以此来实现服务器与客户端的双向通信。
长轮询是对原有的询问技术的一种更有效的利用方式,但是向服务器发送重复请求会浪费资源,这需要为每个新传入的请求建立连接,并解析请求的 HTTP 头部,执行对新数据的查询,并且必须生成和交付响应,但是交付的响应往往是没有新数据的。然后又必须关闭连接并清除所有资源。这就对浏览器的性能造成了很大的浪费。直至2008年Websocket被首次提出,时至今日,Websocket已被所有的主流浏览器所支持,前景良好。
3.Websocket的特点
- 建立在 TCP /IP堆栈之上的一个微型传输层,服务器端的实现比较容易。
- 与 HTTP 协议有着良好的兼容性。并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。
- 数据格式比较轻量,性能开销小,通信高效。
- 可以发送文本,也可以发送二进制数据。
- 没有同源限制,客户端可以与任意服务器通信。
4.简单的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);
5.Websocket心跳机制
由于Websocket下客户端和服务器之间的联系是长时间存在的,有时会就会存在用户长时间未进行操作,也就是客户端和服务器之间长时间不存在通信,此时服务器端是很难判断是用户未进行操作还是连接意外中断,因此就产生了Websocket心跳机制和重连机制。心跳机制是客户端每隔一段时间就会向服务器发送一个数据包,来让服务器得知连接无恙,而服务器在获取到数据包之后,也会给客户端发送一个数据包,让客户端得知连接无恙,倘若出现问题,则代表连接出现问题,进行重连。