前面已经学习了WebSocket API,包括事件、方法和属性。详情:WebSocket(二)--API  WebSocket是基于事件驱动,支持全双工通信。下面通过三个简单例子体验一下。

简单开始

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

2.安装ws模块

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

3.server.js

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

  1. var WebSocketServer = require('ws').Server,
  2. wss = new WebSocketServer({ port: 8181 });
  3. wss.on('connection', function (ws) {
  4. console.log('client connected');
  5. ws.on('message', function (message) {
  6. console.log(message);
  7. });
  8. });

4.建立一个client.html。

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

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

页面:

  1. <html xmlns="http://www.w3.org/1999/xhtml">
  2. <head>
  3. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  4. <title>WebSocket Echo Demo</title>
  5. <meta name="viewport" content="width=device-width, initial-scale=1"/>
  6. <link href="../bootstrap-3.3.5/css/bootstrap.min.css" rel="stylesheet" />
  7. <script src="../js/jquery-1.12.3.min.js"></script>
  8. <script src="../js/jquery-1.12.3.min.js"></script>
  9. <script src="../bootstrap-3.3.5/js/bootstrap.min.js"></script>
  10. <script>
  11. var ws = new WebSocket("ws://localhost:8181");
  12. ws.onopen = function (e) {
  13. console.log('Connection to server opened');
  14. }
  15. function sendMessage() {
  16. ws.send($('#message').val());
  17. }
  18. </script>
  19. </head>
  20.  
  21. <body >
  22. <div class="vertical-center">
  23. <div class="container">
  24. <p>&nbsp;</p>
  25. <form role="form" id="chat_form" onsubmit="sendMessage(); return false;">
  26. <div class="form-group">
  27. <input class="form-control" type="text" name="message" id="message"
  28. placeholder="Type text to echo in here" value="" />
  29. </div>
  30. <button type="button" id="send" class="btn btn-primary"
  31. onclick="sendMessage();">
  32. Send!
  33. </button>
  34. </form>
  35. </div>
  36. </div>
  37. </body>
  38. </html>

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

模拟股票

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

服务端:

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

  1. var stocks = {
  2. "AAPL": 95.0,
  3. "MSFT": 50.0,
  4. "AMZN": 300.0,
  5. "GOOG": 550.0,
  6. "YHOO": 35.0
  7. }
  8. function randomInterval(min, max) {
  9. return Math.floor(Math.random() * (max - min + 1) + min);
  10. }
  11. var stockUpdater;
  12. var randomStockUpdater = function() {
  13. for (var symbol in stocks) {
  14. if(stocks.hasOwnProperty(symbol)) {
  15. var randomizedChange = randomInterval(-150, 150);
  16. var floatChange = randomizedChange / 100;
  17. stocks[symbol] += floatChange;
  18. }
  19. }
  20. var randomMSTime = randomInterval(500, 2500);
  21. stockUpdater = setTimeout(function() {
  22. randomStockUpdater();
  23. }, randomMSTime);
  24. }
  25. randomStockUpdater();

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

  1. wss.on('connection', function (ws) {
  2. var sendStockUpdates = function (ws) {
  3. if (ws.readyState == 1) {
  4. var stocksObj = {};
  5. for (var i = 0; i < clientStocks.length; i++) {
  6. var symbol = clientStocks[i];
  7. stocksObj[symbol] = stocks[symbol];
  8. }
  9. if (stocksObj.length !== 0) {
  10. ws.send(JSON.stringify(stocksObj));//需要将对象转成字符串。WebSocket只支持文本和二进制数据
  11. console.log("更新", JSON.stringify(stocksObj));
  12. }
  13.  
  14. }
  15. }
  16. var clientStockUpdater = setInterval(function () {
  17. sendStockUpdates(ws);
  18. }, 1000);
  19. ws.on('message', function (message) {
  20. var stockRequest = JSON.parse(message);//根据请求过来的数据来更新。
  21. console.log("收到消息", stockRequest);
  22. clientStocks = stockRequest['stocks'];
  23. sendStockUpdates(ws);
  24. });

客户端:

建立连接:

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

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

  1. var isClose = false;
  2. var stocks = {
  3. "AAPL": 0, "MSFT": 0, "AMZN": 0, "GOOG": 0, "YHOO": 0
  4. };
  5. function updataUI() {
  6. ws.onopen = function (e) {
  7. console.log('Connection to server opened');
  8. isClose = false;
  9. ws.send(JSON.stringify(stock_request));
  10. console.log("sened a mesg");
  11. }
  12. //更新UI
  13. var changeStockEntry = function (symbol, originalValue, newValue) {
  14. var valElem = $('#' + symbol + ' span');
  15. valElem.html(newValue.toFixed(2));
  16. if (newValue < originalValue) {
  17. valElem.addClass('label-danger');
  18. valElem.removeClass('label-success');
  19. } else if (newValue > originalValue) {
  20. valElem.addClass('label-success');
  21. valElem.removeClass('label-danger');
  22. }
  23. }
  24. // 处理受到的消息
  25. ws.onmessage = function (e) {
  26. var stocksData = JSON.parse(e.data);
  27. console.log(stocksData);
  28. for (var symbol in stocksData) {
  29. if (stocksData.hasOwnProperty(symbol)) {
  30. changeStockEntry(symbol, stocks[symbol], stocksData[symbol]);
  31. stocks[symbol] = stocksData[symbol];
  32. }
  33. }
  34. };
  35. }
  36.  
  37. updataUI();

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

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

实时聊天

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

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

2.服务端消息发送

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

  1. function wsSend(type, client_uuid, nickname, message) {
  2. for (var i = 0; i < clients.length; i++) {
  3. var clientSocket = clients[i].ws;
  4. if (clientSocket.readyState === WebSocket.OPEN) {
  5. clientSocket.send(JSON.stringify({
  6. "type": type,
  7. "id": client_uuid,
  8. "nickname": nickname,
  9. "message": message
  10. }));
  11. }
  12. }
  13. }

3.服务端处理连接

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

  1. wss.on('connection', function(ws) {
  2. var client_uuid = uuid.v4();
  3. var nickname = "AnonymousUser" + clientIndex;
  4. clientIndex += 1;
  5. clients.push({ "id": client_uuid, "ws": ws, "nickname": nickname });
  6. console.log('client [%s] connected', client_uuid);
  7. var connect_message = nickname + " has connected";
  8. wsSend("notification", client_uuid, nickname, connect_message);
  9. console.log('client [%s] connected', client_uuid);
  10. ws.on('message', function(message) {
  11. if (message.indexOf('/nick') === 0) {
  12. var nickname_array = message.split(' ');
  13. if (nickname_array.length >= 2) {
  14. var old_nickname = nickname;
  15. nickname = nickname_array[1];
  16. var nickname_message = "Client " + old_nickname + " changed to " + nickname;
  17. wsSend("nick_update", client_uuid, nickname, nickname_message);
  18. }
  19. } else {
  20. wsSend("message", client_uuid, nickname, message);
  21. }
  22. });

处理连接关闭:

  1. var closeSocket = function(customMessage) {
  2. for (var i = 0; i < clients.length; i++) {
  3. if (clients[i].id == client_uuid) {
  4. var disconnect_message;
  5. if (customMessage) {
  6. disconnect_message = customMessage;
  7. } else {
  8. disconnect_message = nickname + " has disconnected";
  9. }
  10. wsSend("notification", client_uuid, nickname, disconnect_message);
  11. clients.splice(i, 1);
  12. }
  13. }
  14. };
  15. ws.on('close', function () {
  16. closeSocket();
  17. });

4.客户端

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

  1. <div class="vertical-center">
  2. <div class="container">
  3. <ul id="messages" class="list-unstyled"></ul>
  4. <hr/>
  5. <form role="form" id="chat_form" onsubmit="sendMessage(); return false;">
  6. <div class="form-group">
  7. <input class="form-control" type="text" id="message" name="message"
  8. placeholder="Type text to echo in here" value="" autofocus/>
  9. </div>
  10. <button type="button" id="send" class="btn btn-primary"
  11. onclick="sendMessage();">
  12. Send Message
  13. </button>
  14.  
  15. </form>
  16. <div class="form-group"><span>nikename:</span><input id="name" type="text" /> <button class="btn btn-sm btn-info" onclick="changName();">change</button></div>
  17. </div>
  18. </div>

js:

  1. //建立连接
  2. var ws = new WebSocket("ws://localhost:8181");
  3. var nickname = "";
  4. ws.onopen = function (e) {
  5. console.log('Connection to server opened');
  6. }
  7. //显示
  8. function appendLog(type, nickname, message) {
  9. if (typeof message == "undefined") return;
  10. var messages = document.getElementById('messages');
  11. var messageElem = document.createElement("li");
  12. var preface_label;
  13. if (type === 'notification') {
  14. preface_label = "<span class=\"label label-info\">*</span>";
  15. } else if (type == 'nick_update') {
  16. preface_label = "<span class=\"label label-warning\">*</span>";
  17. } else {
  18. preface_label = "<span class=\"label label-success\">"
  19. + nickname + "</span>";
  20. }
  21. var message_text = "<h2>" + preface_label + "&nbsp;&nbsp;"
  22. + message + "</h2>";
  23. messageElem.innerHTML = message_text;
  24. messages.appendChild(messageElem);
  25. }
  26. //收到消息处理
  27. ws.onmessage = function (e) {
  28. var data = JSON.parse(e.data);
  29. nickname = data.nickname;
  30. appendLog(data.type, data.nickname, data.message);
  31. console.log("ID: [%s] = %s", data.id, data.message);
  32. }
  33. ws.onclose = function (e) {
  34. appendLog("Connection closed");
  35. console.log("Connection closed");
  36. }
  37. //发送消息
  38. function sendMessage() {
  39. var messageField = document.getElementById('message');
  40. if (ws.readyState === WebSocket.OPEN) {
  41. ws.send(messageField.value);
  42. }
  43. messageField.value = '';
  44. messageField.focus();
  45. }
  46. //修改名称
  47. function changName() {
  48. var name = $("#name").val();
  49. if (ws.readyState === WebSocket.OPEN) {
  50. ws.send("/nick " + name);
  51. }
  52. }

运行结果:

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

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

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

源码:http://pan.baidu.com/s/1c2FfKbA

源码:http://pan.baidu.com/s/1o8KRmUQ  加入了socket.io的实现。

API:WebSocket API

相关:websoket使用Protocol Buffers3.0传输

WebSocket 学习(三)--用nodejs搭建服务器的更多相关文章

  1. nodejs搭建服务器 和 操作数据库

    1.express框架:是一个简洁而灵活的 node.js Web应用框架.一般的项目都是基于这个框架开发的.http://www.runoob.com/nodejs/nodejs-express-f ...

  2. WebSocket 学习--用nodejs搭建服务器

    最简单的socket服务端 var net = require("net"); server1 = net.createServer(function(client){ clien ...

  3. 利用nodejs搭建服务器,测试AJAX

    最近学习了AJAX一直没有进行过测试,前今天了解了Noejs搭建本地服务器下就尝试了一下.通过AJAX请求的方式获取HTTP服务器返回数据的代码 首先创建一个serve.js的文件.并写入以下代码. ...

  4. 使用nodejs搭建服务器显示HTML页面

    首先安装express 在命令行输入:npm install express -g 安装完成后可以查看安装情况:npm ls -g 然后创建server.js文件 var express = requ ...

  5. Swoole学习(三)Swoole之UDP服务器的创建

    环境:Centos6.4,PHP环境:PHP7 <?php //创建UCP服务器(UDP服务器相对于TCP服务器通信更可靠些) /** * $host 是swoole需要监听的ip,如果要监听本 ...

  6. spring学习 三 框架的搭建

    1 导入jar包 spring启来最少要5个包,四个核心包和一个依赖的日志包 2 创建配置文件 在dynamic web project下的src目录下,创建一个spring的xml配置文件,名称可以 ...

  7. 使用NodeJs搭建的小型web应用

    原文英文链接:http://www.nodebeginner.org 中文翻译链接:http://www.nodebeginner.org/index-zh-cn.html 学习链接:一本全面的Nod ...

  8. 用nodejs搭建类似于C++的服务器后台.类似网易pomelo

    实际的情况,用nodejs跑业务,非常的快,只要用好其无阻塞和回调这两点,处理速度真的是杠杠的. 从年初开始,我用nodejs搭建了类似C++的服务器后台,也想和做同样的事情的朋友分享,本服务平台因为 ...

  9. SpringMVC 学习 十 SSM环境搭建(三)springMVC文件配置

    SpringMVC文件配置的详细过程,可以查看springMVC环境搭建的注解配置篇<springMVC学习三 注解开发环境搭建> <?xml version="1.0&q ...

随机推荐

  1. (转载)开始iOS 7中自动布局教程(一)

    这篇教程的前半部分被翻译出来很久了,我也是通过这个教程学会的IOS自动布局.但是后半部分(即本篇)一直未有翻译,正好最近跳坑翻译,就寻来这篇教程,进行翻译.前半部分已经转载至本博客,后半部分即本篇.学 ...

  2. C#_闭包陷阱

    如果匿名方法(Lambda表达式)引用了某个局部变量,编译器就会自动将该引用提升到该闭包对象中. 即将for循环中的变量i修改成了引用闭包对象的公共变量i.这样一来,即使代码执行后离开了原局部变量i的 ...

  3. python获取当前时间的用法

    1.先导入库:import datetime 2.获取当前日期和时间:now_time = datetime.datetime.now() 3.格式化成我们想要的日期:strftime() 比如:“2 ...

  4. DBImport v3.3 中文版发布:数据库数据互导及文档生成工具(IT人员必备)

    前言: 好久没写文了, 距离上一篇文章是3个月前的事了,虽然工作很忙,主要还是缺少写作的内容和激情,所以没怎么动手. 之前有一个来月不断面试不同层次来应聘的人员,很有想写文的冲动,后来还是忍住了. 估 ...

  5. 【性能为王】从PHP源码剖析array_keys和array_unique

    之前在[译]更快的方式实现PHP数组去重这篇文章里讨论了使用array_flip后再调用array_keys函数替换直接调用array_unique函数实现数组去重性能较好.由于原文没有给出源码分析和 ...

  6. Hadoop学习笔记—21.Hadoop2的改进内容简介

    Hadoop2相比较于Hadoop1.x来说,HDFS的架构与MapReduce的都有较大的变化,且速度上和可用性上都有了很大的提高,Hadoop2中有两个重要的变更: (1)HDFS的NameNod ...

  7. 关于新书《修炼之道:.NET开发要点精讲》的各种说明

    索引 新书介绍 新书封面 新书目录 试读章节 原稿试读 网购地址 规格参数 反馈方式 一些感谢 附加说明 1.新书介绍 从2013年年底到2014年9月,历时将近10个月,这本书终于看到了“出版发行” ...

  8. 企业IT管理员IE11升级指南【7】—— Win7和Win8.1上的IE11功能对比

    企业IT管理员IE11升级指南 系列: [1]—— Internet Explorer 11增强保护模式 (EPM) 介绍 [2]—— Internet Explorer 11 对Adobe Flas ...

  9. 新浪计数业务之Redis

    今天听一个同事说新浪使用的是Redis,于是自己将研究的过程整理出来以备后用. 我们都知道微博这玩意儿现在很火,新浪作为国内最早使用redis,并且是国内最大的redis使用者,当然备受人们关注.新浪 ...

  10. Android开发学习之路-Volley源码解析

    从简单的StringRequest入手看看Volley的工作机制. 先简单说下Volley的用法: ① 获取一个RequestQueue mRequestQueue = Volley.newReque ...