Node构建WebSocket服务

1,WebSocket和Http的区别?

HTTP只能由客户端发起通信,不能主动获取实时数据。常用的方法轮询,就是用一个定时器,不停地发http请求(非常浪费资源)。

我们希望的场景是这样的:服务端数据发生变化,主动向客户端推送最新信息,客户端也可以主动向服务器发送信息。这个时候

服务器推送技术WebSocket就出场了。

2,WebSocket 客户端提供的使用方法

//1,WebSocket 实例化
var ws = new WebSocket("ws://localhost:8181");
    ws.onopen = function (e) {
        console.log('客户端(client):与服务器的连接已打开')
  }
2,readyState属性返回实例对象的当前状态

//CONNECTING:值为0,表示正在连接。
//OPEN:值为1,表示连接成功,可以通信了。
//CLOSING:值为2,表示连接正在关闭。
//CLOSED:值为3,表示连接已经关闭,或者打开连接失败。

 

3,webSocket.onopen //指定连接成功后的回调函数
4,webSocket.onclose //指定连接关闭后的回调函数
5,webSocket.onmessage //收到服务器数据后的回调函数
6,webSocket.send //方法用于向服务器发送数据
7,webSocket.bufferedAmount //表示还有多少字节的二进制数据没有发送出去。它可以用来判断发送是否结束。
8,webSocket.onerror //指定报错时的回调函数。

ws.onopen = function () {
  ws.send('连接服务器成功');
}

//多个回调函数用
ws.addEventListener('open', function (event) {
  ws.send('Hello Server!');
});

3,WebSocket 服务端实现

不用全看,文档不是很全,技术是实现业务方法

我简单写了几个demo

3.1客户端向服务端发送消息

安装node,和ws

npm install ws

 

新建文件

客户端代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <link href="../bootstrap-3.3.5/css/bootstrap.min.css" rel="stylesheet" />
    <script src="../js/jquery-1.12.3.min.js"></script>
    <script src="../bootstrap-3.3.5/js/bootstrap.min.js"></script>
</head>

<body>

    <div class="vertical-center">
        <div class="container">
            <!-- 客户端加一个简单的input输入框和一个发送按钮 -->
            <form role="form" id="chat_form" onsubmit="sendMessage(); return false;" style="margin-top:100px;">
                <div class="form-group">
                    <input class="form-control" type="text" name="message" id="message" value="" />
                </div>
                <button type="button" id="send" class="btn btn-primary" onclick="sendMessage();">
                    发送
                </button>
            </form>
        </div>
    </div>
</body>
<script>
    //WebSocket实例化
    var ws = new WebSocket("ws://localhost:8181");
    ws.onopen = function (e) {
        //成功连接服务器回调
        console.log('客户端(client):与服务器的连接已打开')
    }

    function sendMessage() {
        ws.send($('#message').val());
    };
</script>

</html>

 

服务端代码

var WebSocketServer = require('ws').Server,
wss = new WebSocketServer({ port: 8181 });//服务端口8181
wss.on('connection', function (ws) {
    console.log('服务端:客户端已连接');
    ws.on('message', function (message) {
        //打印客户端监听的消息
        console.log(message);
    });
});

启动node服务

3.2服务端图推送消息到客户端

场景:车辆速度实时讲课监控。每三秒客户端更新一次信息

同样客户端代码

<!DOCTYPE html>
<html lang="en">

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>服务器推送消息</title>
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link href="../bootstrap-3.3.5/css/bootstrap.min.css" rel="stylesheet" />
    <script src="../js/jquery-1.12.3.min.js"></script>
    <script src="../bootstrap-3.3.5/js/bootstrap.min.js"></script>
</head>

<body>
    <div class="vertical-center">
        <div class="container">
            <h1>检测车辆速度</h1>
            <button class="btn btn-primary">开始</button>
            <button class="btn btn-danger">停止</button>
            <table class="table" id="stockTable">
                <thead>
                    <tr>
                        <th>车牌号</th>
                        <th>速度</th>
                    </tr>
                </thead>
                <tbody id="stockRows">
                    <tr>
                        <td>
                            <h3>A11111</h3>
                        </td>
                        <td id="A11111">
                            <h3><span class="label label-default label-success">00.00</span></h3>
                        </td>
                    </tr>
                    <tr>
                        <td>
                            <h3>A22222</h3>
                        </td>
                        <td id="A22222">
                            <h3><span class="label label-default label-success">00.00</span></h3>
                        </td>
                    </tr>
                </tbody>
            </table>
        </div>
    </div>
    <script>
        var ws = new WebSocket("ws://localhost:8181");
        var stock_request = {
            "speed": ["A11111", "A22222"]
        };
        var isClose = false;
        var speed = {
            "A11111": 0,
            "A22222": 0,
        };
        //更新视图
        function updataSource() {
            ws.onopen = function (e) {
                console.log('连接服务器成功');
                isClose = false;
                ws.send(JSON.stringify(stock_request));
                console.log("发送消息成功");
            }
            // UI update function
            var changeSpeedEntry = function (item, newValue) {
                var valElem = $('#' + item + ' span');
                valElem.html(newValue.toFixed(2));
            }
            // 客户端WebSocket 监听消息并处理程序
            ws.onmessage = function (e) {
                var speedData = JSON.parse(e.data);
                console.log("收到数据:" + speedData);
                for (var item in speedData) {
                    if (speedData.hasOwnProperty(item)) {
                        changeSpeedEntry(item, speedData[item]);
                        speed[item] = speedData[item];
                    }
                }
            };
        }

        //业务代码
        updataSource();

        $(".btn-primary").click(function () {
            if (isClose) {
                ws = new WebSocket("ws://localhost:8181");
            }
            updataSource();
        });
        $(".btn-danger").click(function () {
            ws.close();
        });

        ws.onclose = function (e) {
            console.log("断开连接", e);
            isClose = true;
        };
    </script>
</body>

</html>

服务端代码

var WebSocketServer = require('ws').Server,
    wss = new WebSocketServer({
        port: 8181
    }); //服务端口8181
var speed = {
    "A11111": 95.0,
    "A22222": 50.0
}

var randomSpeedUpdater = function () {
    for (var item in speed) {

        var randomizedChange = Math.random(60, 120);
        speed[item] += randomizedChange;

    }
}
//模拟车速实时变化

setInterval(
    function () {
        randomSpeedUpdater();
    }, 1000)

var clientSpeeds = [];
wss.on('connection', function (ws) {
    var sendSpeedUpdates = function (ws) {
        if (ws.readyState == 1) {
            var speedObj = {};
            for (var i = 0; i < clientSpeeds.length; i++) {
                var item = clientSpeeds[i];
                speedObj[item] = speed[item];
            }
            if (speedObj.length !== 0) {
                ws.send(JSON.stringify(speedObj)); //需要将对象转成字符串。WebSocket只支持文本和二进制数据,推送消息
                console.log("服务器:更新数据", JSON.stringify(speedObj));
            }

        }
    }

    //每三秒发送一次
    var clientSpeedUpdater = setInterval(function () {
        sendSpeedUpdates(ws);
    }, 3000);
    ws.on('message', function (message) {
        var stockRequest = JSON.parse(message); //根据请求过来的数据来更新。
        console.log("服务器:收到消息", stockRequest);
        clientSpeeds = stockRequest['speed'];
        sendSpeedUpdates(ws);
    });
    ws.on('close', function () {
        if (clientSpeedUpdater > 0) {
            //断开连接清楚定时器
            clearInterval(clientSpeedUpdater);
        }
    });
});

启动服务,效果截图(我用的pm2管理进程,可以直接node启动)

3.3简单实现聊天场景(待续。。。)

 

posted @ 2019-05-21 10:30  有什么奇怪  阅读(19584)  评论(1编辑  收藏  举报