Websocket

1.什么是Websocket

WebSocket 是一种在单个TCP连接上进行全双工通信的协议。WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。

  • Tcp,英文全称为Transmission Control Protocol,是一种面向连接的、可靠的、基于字节流的传输层通信协议。通俗一点理解就是在网络世界里的一种信息传递方式,像是现实生活中的写信等等,是电子设备传递信息的一种方式。
  • 全双工,通讯传输的一种方式。除了全双工外,还有半双工和单工。单工指数据只能单向传输,半双工指数据可以双向传输,但是同一时刻只能有一方传输数据,全双工就是指双方可以同时传数据。通俗一点可以理解为单工是单向车道,半双工是潮汐车道,全双工就是双向车道。

2.Websocket背景

起初,浏览器是request——response模式,只有当用户向浏览器发送了请求,浏览器才能将数据发送给用户,这种模式下并不支持浏览器主动向用户发送数据,像如今的热门推送,在当时都是无法实现的,当时能做到的最多就是以静态页面的形式推送信息,根本无法和今天的动态获取热门信息相比。为了实现web 页面和服务器之间的实时交互通信,当时的开发人员滥用 XMLHttpRequest 来实现这一功能。最出名的就是长轮询,也就是让 HTTP 连接保持打开状态意味着只要连接保持打开状态,服务器就可以继续持续响应数据,以此来实现服务器与客户端的双向通信。

长轮询是对原有的询问技术的一种更有效的利用方式,但是向服务器发送重复请求会浪费资源,这需要为每个新传入的请求建立连接,并解析请求的 HTTP 头部,执行对新数据的查询,并且必须生成和交付响应,但是交付的响应往往是没有新数据的。然后又必须关闭连接并清除所有资源。这就对浏览器的性能造成了很大的浪费。直至2008年Websocket被首次提出,时至今日,Websocket已被所有的主流浏览器所支持,前景良好。

3.Websocket的特点

  1. 建立在 TCP /IP堆栈之上的一个微型传输层,服务器端的实现比较容易。
  2. 与 HTTP 协议有着良好的兼容性。并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。
  3. 数据格式比较轻量,性能开销小,通信高效。
  4. 可以发送文本,也可以发送二进制数据。
  5. 没有同源限制,客户端可以与任意服务器通信。

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心跳机制和重连机制。心跳机制是客户端每隔一段时间就会向服务器发送一个数据包,来让服务器得知连接无恙,而服务器在获取到数据包之后,也会给客户端发送一个数据包,让客户端得知连接无恙,倘若出现问题,则代表连接出现问题,进行重连。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值