用nodejs搭建websocket服务器


Posted in NodeJs onJanuary 23, 2017

 简单开始

1.安装node。https://nodejs.org/en/ 

2.安装ws模块

ws:是nodejs的一个WebSocket库,可以用来创建服务。 https://github.com/websockets/ws

用nodejs搭建websocket服务器

3.server.js

在项目里面新建一个server.js,创建服务,指定8181端口,将收到的消息log出来。

var WebSocketServer = require('ws').Server,
wss = new WebSocketServer({ port: 8181 });
wss.on('connection', function (ws) {
  console.log('client connected');
  ws.on('message', function (message) {
    console.log(message);
  });
});

4.建立一个client.html。

在页面上建立一个WebSocket的连接。用send方法发送消息。

var ws = new WebSocket("ws://localhost:8181");
  ws.onopen = function (e) {
    console.log('Connection to server opened');
  }
  function sendMessage() {
    ws.send($('#message').val());
  }

页面: 

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <title>WebSocket Echo Demo</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="../js/jquery-1.12.3.min.js"></script>
  <script src="../bootstrap-3.3.5/js/bootstrap.min.js"></script>
  <script>
  var ws = new WebSocket("ws://localhost:8181");
  ws.onopen = function (e) {
    console.log('Connection to server opened');
  }
  function sendMessage() {
    ws.send($('#message').val());
  }
  </script>
</head>

<body >
  <div class="vertical-center">
    <div class="container">
      <p> </p>
      <form role="form" id="chat_form" onsubmit="sendMessage(); return false;">
        <div class="form-group">
          <input class="form-control" type="text" name="message" id="message"
              placeholder="Type text to echo in here" value="" />
        </div>
        <button type="button" id="send" class="btn btn-primary"
            onclick="sendMessage();">
          Send!
        </button>
      </form>
    </div>
  </div>
</body>
</html>

运行之后如下,服务端即时获得客户端的消息。

用nodejs搭建websocket服务器

模拟股票

上面的例子很简单,只是为了演示如何运用nodejs的ws创建一个WebSocket服务器。且可以接受客户端的消息。那么下面这个例子演示股票的实时更新。客服端只需要连接一次,服务器端会不断地发送新数据,客户端收数据后更新UI.页面如下,有五只股票,开始和停止按钮测试连接和关闭。

用nodejs搭建websocket服务器

 服务端:

 1.模拟五只股票的涨跌。

var stocks = {
  "AAPL": 95.0,
  "MSFT": 50.0,
  "AMZN": 300.0,
  "GOOG": 550.0,
  "YHOO": 35.0
}
function randomInterval(min, max) {
  return Math.floor(Math.random() * (max - min + 1) + min);
}
var stockUpdater;
var randomStockUpdater = function() {
  for (var symbol in stocks) {
    if(stocks.hasOwnProperty(symbol)) {
      var randomizedChange = randomInterval(-150, 150);
      var floatChange = randomizedChange / 100;
      stocks[symbol] += floatChange;
    }
  }
  var randomMSTime = randomInterval(500, 2500);
  stockUpdater = setTimeout(function() {
    randomStockUpdater();
  }, randomMSTime);
}
randomStockUpdater();

2.连接建立之后就开始更新数据

wss.on('connection', function (ws) {
  var sendStockUpdates = function (ws) {
    if (ws.readyState == 1) {
      var stocksObj = {};
      for (var i = 0; i < clientStocks.length; i++) {
       var symbol = clientStocks[i];
        stocksObj[symbol] = stocks[symbol];
      }
      if (stocksObj.length !== 0) {
        ws.send(JSON.stringify(stocksObj));//需要将对象转成字符串。WebSocket只支持文本和二进制数据
        console.log("更新", JSON.stringify(stocksObj));
      }
      
    }
  }
  var clientStockUpdater = setInterval(function () {
    sendStockUpdates(ws);
  }, 1000);
  ws.on('message', function (message) {
    var stockRequest = JSON.parse(message);//根据请求过来的数据来更新。
    console.log("收到消息", stockRequest);
    clientStocks = stockRequest['stocks'];
    sendStockUpdates(ws);
  });

客户端:

建立连接:

var ws = new WebSocket("ws://localhost:8181");

onopen直接只有在连接成功后才会触发,在这个时候将客户端需要请求的股票发送给服务端。

var isClose = false;
  var stocks = {
    "AAPL": 0, "MSFT": 0, "AMZN": 0, "GOOG": 0, "YHOO": 0
  };
  function updataUI() {
    ws.onopen = function (e) {
      console.log('Connection to server opened');
      isClose = false;
      ws.send(JSON.stringify(stock_request));
      console.log("sened a mesg");
    }
    //更新UI
    var changeStockEntry = function (symbol, originalValue, newValue) {
      var valElem = $('#' + symbol + ' span');
      valElem.html(newValue.toFixed(2));
      if (newValue < originalValue) {
        valElem.addClass('label-danger');
        valElem.removeClass('label-success');
      } else if (newValue > originalValue) {
        valElem.addClass('label-success');
        valElem.removeClass('label-danger');
      }
    }
    // 处理受到的消息
    ws.onmessage = function (e) {
      var stocksData = JSON.parse(e.data);
      console.log(stocksData);
      for (var symbol in stocksData) {
        if (stocksData.hasOwnProperty(symbol)) {
          changeStockEntry(symbol, stocks[symbol], stocksData[symbol]);
          stocks[symbol] = stocksData[symbol];
        }
      }
    };
  }

  updataUI();

运行效果如下:只需要请求一次,数据就会不断的更新,效果是不是很赞,不用轮询,也不用长连接那么麻烦了。文章末尾会附上所有源码。

(美股的涨跌和A股的颜色是反的,即红跌绿涨)

用nodejs搭建websocket服务器

实时聊天

上面的例子是连接建立之后,服务端不断给客户端发送数据。接下来例子是一个简单的聊天室类的例子。可以建立多个连接。

1.安装node-uuid模块,用来给每个连接一个唯一号。

用nodejs搭建websocket服务器

2.服务端消息发送

消息类型分notification和message两种,前者是提示信息,后者是聊天内容。消息还包含一个id、昵称和消息内容。在上一节有学习到readyState有四个值,OPEN表示连接建立可以发送消息。如果页面关闭了,为WebSocket.CLOSE。

function wsSend(type, client_uuid, nickname, message) {
  for (var i = 0; i < clients.length; i++) {
    var clientSocket = clients[i].ws;
    if (clientSocket.readyState === WebSocket.OPEN) {
      clientSocket.send(JSON.stringify({
        "type": type,
        "id": client_uuid,
        "nickname": nickname,
        "message": message
      }));
    }
  }
}

3.服务端处理连接

每新增加一个连接,都会发送一条匿名用户的加入的提示消息,如果消息中带有“/nick” 认为这一个修改昵称的消息。然后更新客户端的昵称。其他都会当做聊天消息处理。

wss.on('connection', function(ws) {
  var client_uuid = uuid.v4();
  var nickname = "AnonymousUser" + clientIndex;
  clientIndex += 1;
  clients.push({ "id": client_uuid, "ws": ws, "nickname": nickname });
  console.log('client [%s] connected', client_uuid);
  var connect_message = nickname + " has connected";
  wsSend("notification", client_uuid, nickname, connect_message);
  console.log('client [%s] connected', client_uuid);
  ws.on('message', function(message) {
    if (message.indexOf('/nick') === 0) {
      var nickname_array = message.split(' ');
      if (nickname_array.length >= 2) {
        var old_nickname = nickname;
        nickname = nickname_array[1];
        var nickname_message = "Client " + old_nickname + " changed to " + nickname;
        wsSend("nick_update", client_uuid, nickname, nickname_message);
      }
    } else {
      wsSend("message", client_uuid, nickname, message);
    }
  });

处理连接关闭:

var closeSocket = function(customMessage) {
    for (var i = 0; i < clients.length; i++) {
      if (clients[i].id == client_uuid) {
        var disconnect_message;
        if (customMessage) {
          disconnect_message = customMessage;
        } else {
          disconnect_message = nickname + " has disconnected";
        }
        wsSend("notification", client_uuid, nickname, disconnect_message);
        clients.splice(i, 1);
      }
    }
  };
  ws.on('close', function () {
    closeSocket();
  });

4.客户端

 没有启动时,页面如下,change按钮用来修改昵称。

用nodejs搭建websocket服务器

<div class="vertical-center">
    <div class="container">
      <ul id="messages" class="list-unstyled"></ul>
      <hr/>
      <form role="form" id="chat_form" onsubmit="sendMessage(); return false;">
        <div class="form-group">
          <input class="form-control" type="text" id="message" name="message"
              placeholder="Type text to echo in here" value="" autofocus/>
        </div>
        <button type="button" id="send" class="btn btn-primary"
            onclick="sendMessage();">
          Send Message
        </button>

      </form>
      <div class="form-group"><span>nikename:</span><input id="name" type="text" /> <button class="btn btn-sm btn-info" onclick="changName();">change</button></div>
    </div>
  </div>

js:

//建立连接
    var ws = new WebSocket("ws://localhost:8181");
    var nickname = "";
    ws.onopen = function (e) {
      console.log('Connection to server opened');
    }
    //显示
    function appendLog(type, nickname, message) {
      if (typeof message == "undefined") return;
      var messages = document.getElementById('messages');
      var messageElem = document.createElement("li");
      var preface_label;
      if (type === 'notification') {
        preface_label = "<span class=\"label label-info\">*</span>";
      } else if (type == 'nick_update') {
        preface_label = "<span class=\"label label-warning\">*</span>";
      } else {
        preface_label = "<span class=\"label label-success\">"
        + nickname + "</span>";
      }
      var message_text = "<h2>" + preface_label + "  "
      + message + "</h2>";
      messageElem.innerHTML = message_text;
      messages.appendChild(messageElem);
    }
    //收到消息处理
    ws.onmessage = function (e) {
      var data = JSON.parse(e.data);
      nickname = data.nickname;
      appendLog(data.type, data.nickname, data.message);
      console.log("ID: [%s] = %s", data.id, data.message);
    }
    ws.onclose = function (e) {
      appendLog("Connection closed");
      console.log("Connection closed");
    }
    //发送消息
    function sendMessage() {
      var messageField = document.getElementById('message');
      if (ws.readyState === WebSocket.OPEN) {
        ws.send(messageField.value);
      }
      messageField.value = '';
      messageField.focus();
    }
    //修改名称
    function changName() {
      var name = $("#name").val();
      if (ws.readyState === WebSocket.OPEN) {
        ws.send("/nick " + name);
      }
    }

 运行结果:

 页面关闭之后,连接马上断开。

用nodejs搭建websocket服务器

 这种实时响应的体验简直不能太爽,代码也清爽了,前端体验也更好,客户端不用一直发请求,服务端不用等着被轮询。

 小结:上面例子的代码都很好理解,接下来学习WebSocket协议。

demo下载:http://xiazai.3water.com/201701/yuanma/websocket_3water.rar

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

NodeJs 相关文章推荐
PHPStorm 2020.1 调试 Nodejs的多种方法详解
Sep 17 NodeJs
nodejs获取本机内网和外网ip地址的实现代码
Jun 01 NodeJs
Nodejs进阶:基于express+multer的文件上传实例
Nov 21 NodeJs
nodejs 简单实现动态html的方法
May 12 NodeJs
NodeJS如何实现同步的方法示例
Aug 24 NodeJs
Nodejs使用Mongodb存储与提供后端CRD服务详解
Sep 04 NodeJs
nodejs 使用nodejs-websocket模块实现点对点实时通讯
Nov 28 NodeJs
nodejs 使用 js 模块的方法实例详解
Dec 04 NodeJs
详解NodeJS Https HSM双向认证实现
Mar 12 NodeJs
nodejs读取图片返回给浏览器显示
Jul 25 NodeJs
NodeJs内存占用过高的排查实战记录
May 10 NodeJs
node快速搭建后台的实现步骤
Feb 18 NodeJs
NodeJS遍历文件生产文件列表功能示例
Jan 22 #NodeJs
nodejs实现发出蜂鸣声音(系统报警声)的方法
Jan 18 #NodeJs
nodejs的压缩文件模块archiver用法示例
Jan 18 #NodeJs
nodejs 实现钉钉ISV接入的加密解密方法
Jan 16 #NodeJs
简单实现nodejs上传功能
Jan 14 #NodeJs
基于NodeJS+MongoDB+AngularJS+Bootstrap开发书店案例分析
Jan 12 #NodeJs
NodeJS实现客户端js加密
Jan 09 #NodeJs
You might like
PHP 服务器配置(使用Apache及IIS两种方法)
2009/06/01 PHP
PHP 读取大文件的X行到Y行内容的实现代码
2013/06/24 PHP
jQuery中的RadioButton,input,CheckBox取值赋值实现代码
2014/02/18 PHP
php绘制一条直线的方法
2015/01/24 PHP
PHP中static关键字以及与self关键字的区别
2015/07/01 PHP
PHP+MySQL统计该库中每个表的记录数并按递减顺序排列的方法
2016/02/15 PHP
PHP实现活动人选抽奖功能
2017/04/19 PHP
php判断/计算闰年的方法小结【三种方法】
2019/07/06 PHP
js取滚动条的尺寸的函数代码
2011/11/30 Javascript
离开当前页面前使用js判断条件提示是否要离开页面
2014/05/02 Javascript
js中实现多态采用和继承类似的方法
2014/08/22 Javascript
一个很有趣3D球状标签云兼容IE8
2014/08/22 Javascript
js弹出对话框方式小结
2015/11/17 Javascript
JS代码实现table数据分页效果
2016/05/26 Javascript
jQuery将表单序列化成一个Object对象的实例
2016/11/29 Javascript
vue.js路由跳转详解
2017/08/28 Javascript
Vue + better-scroll 实现移动端字母索引导航功能
2018/05/07 Javascript
vue中组件的过渡动画及实现代码
2018/11/21 Javascript
Node.js 如何利用异步提升任务处理速度
2019/01/07 Javascript
亲自动手实现vue日历控件
2019/06/26 Javascript
JS错误处理与调试操作实例分析
2020/04/13 Javascript
python实现用户管理系统
2018/01/10 Python
Python实现的统计文章单词次数功能示例
2019/07/08 Python
PyTorch如何搭建一个简单的网络
2020/08/24 Python
利用CSS3制作简单的3d半透明立方体图片展示
2017/03/25 HTML / CSS
施华洛世奇巴西官网:SWAROVSKI巴西
2019/12/03 全球购物
行政办公员自我评价分享
2013/12/14 职场文书
财务支持类个人的自我评价
2014/02/14 职场文书
学习演讲稿范文
2014/05/10 职场文书
效能监察建议书
2014/05/19 职场文书
安全责任书模板
2014/07/22 职场文书
最美孝心少年事迹材料
2014/08/15 职场文书
大学生学习面向未来的赶考思想汇报
2014/09/12 职场文书
女生抽烟检讨书
2014/10/05 职场文书
护理专业自我评价
2015/03/11 职场文书
零基础学java之带参数以及返回值的方法
2022/04/10 Java/Android