初探websocket

140 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第15天,点击查看活动详情

我们知道http是请求应答的模式,基于半双工通信,但是很多时候我们需要有全双工通信,如消息推送这种功能,在没有全双工通信的时候,我们只能用轮询的方式来进行,但是这种方式要服务器不断的请求,资源消耗较大,于是h5提出了新的规范,就是今天要说的websocket

特点

  • websocket是建立在TCP协议之上的。
  • 支持的擦混输类型多,可以是文本也可以是二进制文件。
  • 没有同源限制,不会发生跨域的警告。
  • 协议标志是ws,如果是加密的那么就是wss(这和http和https很像)。

连接过程

我们知道http是通过三次握手建立连接的,断开的时候再进行四次挥手,其过程是一个请求应答的过程,响应的前提是要接收到请求,而websocket是在客户端发起http请求后,经过三次握手建立起TCP连接,htto请求中存放这websocket支持的版本号等具体信息,建立连接后就可以正常通信了,这种通信是全双工通信。

websocket相比较http的缺点和优点

  • 优点

建立连接后,进行通信的请求头是很小的,减少了资源的消耗。

服务器可以向客户端主动推送消息了。

  • 缺点

部分浏览器尚未支持且已经支持的浏览器现在支持的程度和方式也不太一样。

体验websocket

我们通过nodejs-websocket这个包来创建我们的websocket服务,其对websocket进行了一些封装便于我们使用:

  • ws.createServer([options], [callback]):创建一个 server 对象

  • ws.connect(URL, [options], [callback]):创建一个 connect 对象,一般由客户端链接服务端 websocket 服务时创建

服务端代码

var ws = require("nodejs-websocket")
var port = 8010;
var user = 0;

// 创建一个连接
var server = ws.createServer(function (conn) {
    console.log("创建一个新的连接--------");
    user++;
    conn.nickname="user" + user;
    conn.fd="user" + user;
    var mes = {};
    mes.type = "enter";
    mes.data = conn.nickname + " 进来啦"
    broadcast(JSON.stringify(mes)); // 广播

    //向客户端推送消息
    conn.on("text", function (str) {
        console.log("回复 "+str)
        mes.type = "message";
        mes.data = conn.nickname + " 说:    " + str;
        broadcast(JSON.stringify(mes));
    });

    //监听关闭连接操作
    conn.on("close", function (code, reason) {
        console.log("关闭连接");
        mes.type = "leave";
        mes.data = conn.nickname+" 离开了"
        broadcast(JSON.stringify(mes));
    });

    //错误处理
    conn.on("error", function (err) {
        console.log("监听到错误");
        console.log(err);
    });
}).listen(port);

function broadcast(str){
    server.connections.forEach(function(connection){
        connection.sendText(str);
    })
}

客户端代码

<html>

<body>
    <h1>Websocket简易聊天</h1>
    <div id="app">
        <input id="sendMsg" type="text" />
        <button id="submitBtn">发送</button>
    </div>
</body>
<script type="text/javascript">
    //在页面显示聊天内容
    function showMessage(str, type) {
        var div = document.createElement("div");
        div.innerHTML = str;
        if (type == "enter") {
            div.style.color = "blue";
        } else if (type == "leave") {
            div.style.color = "red";
        }
        document.body.appendChild(div);
    }

    //新建一个websocket
    var websocket = new WebSocket("ws://192.168.137.128:8010");
    //打开websocket连接
    websocket.onopen = function () {
        console.log("已经连上服务器----");
        document.getElementById("submitBtn").onclick = function () {
            var txt = document.getElementById("sendMsg").value;
            if (txt) {
                //向服务器发送数据
                websocket.send(txt);
            }
        };
    };
    //关闭连接
    websocket.onclose = function () {
        console.log("websocket close");
    };
    //接收服务器返回的数据
    websocket.onmessage = function (e) {
        var mes = JSON.parse(e.data);   // json格式
        showMessage(mes.data, mes.type);
    };
</script>

</html>

GIF 2022-6-8 20-22-52.gif

可以看到我们的服务器和客户端不在同一个端口,但是一样没有发生跨域问题,说明websocket是不存在同源限制的,我们先开启服务器,对于不同形式的请求我们通过type进行判断,客户端在接受到服务器推送来的消息后进行type的判断后分不同的方式进行展示,可以看到通过广播形式发送的消息,无论你有多少个客户端都可以收到,即使你没有请求,这也就是我们说的websocket不再是请求应答的形式而是可以主动发送消息给我们的客户端的,这也就很好的实现了一个简易的聊天室。