用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 相关文章推荐
轻松创建nodejs服务器(7):阻塞操作的实现
Dec 18 NodeJs
Nodejs中调用系统命令、Shell脚本和Python脚本的方法和实例
Jan 01 NodeJs
Nodejs从有门道无门菜鸟起飞必看教程
Jul 20 NodeJs
nodejs中向HTTP响应传送进程的输出
Mar 19 NodeJs
nodejs个人博客开发第四步 数据模型
Apr 12 NodeJs
nodejs入门教程四:URL相关模块用法分析
Apr 24 NodeJs
Nodejs中使用phantom将html转为pdf或图片格式的方法
Sep 18 NodeJs
nodejs实现的连接MySQL数据库功能示例
Jan 25 NodeJs
nodejs用gulp管理前端文件方法
Jun 24 NodeJs
Nodejs中的JWT和Session的使用
Aug 21 NodeJs
NodeJs实现简易WEB上传下载服务器
Aug 10 NodeJs
Nodejs封装类似express框架的路由实例详解
Jan 05 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读取csc文件并输出
2015/05/21 PHP
WordPress中获取所使用的模板的页面ID的简单方法
2015/12/31 PHP
基于jquery扩展漂亮的CheckBox(自己编写)
2013/11/19 Javascript
JavaScript判断访问的来源是手机还是电脑,用的哪种浏览器
2013/12/12 Javascript
node.js使用nodemailer发送邮件实例
2014/03/10 Javascript
了不起的node.js读书笔记之mongodb数据库交互
2014/12/22 Javascript
小米公司JavaScript面试题
2014/12/29 Javascript
javascript将DOM节点添加到文档的方法实例分析
2015/08/04 Javascript
jQuery制作图片旋转效果
2017/02/02 Javascript
关于在vue-cli中使用微信自动登录和分享的实例
2017/06/22 Javascript
JS实现问卷星自动填问卷脚本并在两秒自动提交功能
2020/06/17 Javascript
[js高手之路]原型式继承与寄生式继承详解
2017/08/28 Javascript
JS实现的数组去除重复数据算法小结
2017/11/17 Javascript
vue cli 全面解析
2018/02/28 Javascript
js合并两个数组生成合并后的key:value数组
2018/05/09 Javascript
vue使用better-scroll实现下拉刷新、上拉加载
2018/11/23 Javascript
基于Fixed定位的框选功能的实现代码
2019/05/13 Javascript
JS中async/await实现异步调用的方法
2019/08/28 Javascript
Vue 3.0双向绑定原理的实现方法
2019/10/23 Javascript
vue 获取元素额外生成的data-v-xxx操作
2020/09/09 Javascript
python用于url解码和中文解析的小脚本(python url decoder)
2013/08/11 Python
Django项目实战之用户头像上传与访问的示例
2018/04/21 Python
解决python爬虫中有中文的url问题
2018/05/11 Python
使用python快速在局域网内搭建http传输文件服务的方法
2019/11/14 Python
Python爬虫抓取指定网页图片代码实例
2020/07/24 Python
耐克巴西官方网站:Nike巴西
2016/08/14 全球购物
时尚孕妇装:Ingrid & Isabel
2019/05/08 全球购物
企业为何需要商业计划书
2013/12/26 职场文书
幼儿园教师工作感言
2014/02/15 职场文书
中国好声音广告词
2014/03/18 职场文书
毕业生实习证明
2014/09/19 职场文书
慈善募捐倡议书
2015/04/27 职场文书
写给消防战士们的一封慰问信
2019/10/07 职场文书
在Windows下安装配置CPU版的PyTorch的方法
2021/04/02 Python
Python 中 Shutil 模块详情
2021/11/11 Python
CSS3实现360度循环旋转功能
2022/02/12 HTML / CSS