Node.js之Websocket技术

我第一次听说websocket之时,HTML5标准尚未公布,当时只有少数前瞻性浏览器携带了这个API。

我对websocket最大的印象是,他可以解决我对“在线聊天系统”开发的疑惑(我一直想不通http如何保持长连接),这样我们无需使用轮询ajax和php无限循环去模拟,还记得2014年初那会我写了一个在线聊天室,那时候我真的应该用websocket技术的,php无限轮询的方式,只要3-4个人在线就可以让linux+apache服务器崩溃。

很可惜,我没有在php上使用过Websocket API,今天是我第一次将这个技术用来实践,使用node.js实现

引入模块

package.json

  1. {
  2. "name":"chat-websocket",
  3. "version":"0.0.1",
  4. "description":"use websocket to create a char server",
  5. "dependencies":{
  6. "express":"latest",
  7. "express-ws":"latest"
  8. }
  9. }

在引入http必备的express框架后,再引入基于express的中间件——express-ws

express-ws是express上的websocket中间件,为express提供了websocket请求处理功能

另外注意:《了不起的node.js》一书中使用的是websocket.io模块,两个东西原理,方法都差不多,我个人觉得io那个老了点,我选择了express-ws模块!主要是因为其与express配合效果更佳,专门为express而设计的中间件,何乐而不用呢?

做个测试

先来看看,node中使用express-ws的基本套路:

index.js

  1. var express = require("express");
  2. //创建express下的http服务
  3. var app = express();
  4. //关联express-ws中间件
  5. var expressWs = require("express-ws")(app);
  6. //express托管静态文件
  7. app.use(express.static(__dirname+'/views',{'index':'index.html'}));
  8. app.ws('/ws',function(ws,req){
  9. ws.on('message',function(msg){
  10. console.log(msg);
  11. })
  12. });;
  13. app.listen(80);

这个index.js是服务端代码

解析:

  • 先引入express模块,并使用express()方法获得app对象
  • 引入express-ws并构造对象,构造函数传入的是app对象,意思大概是绑定到express服务器上
  • 通常接受http请求使用的是app.use(),而websocket请求则使用app.ws(),该方法就是中间件扩展的
  • message事件监听客户端发送的数据,并打印到终端上

views/index.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>测试</title>
  6. </head>
  7. <body>
  8. <input type="text" value="" id="msg">
  9. <button id="submit">提交</button>
  10. </body>
  11. <script>
  12. window.onload=function(){
  13. var ws = new WebSocket('ws://localhost/ws')
  14. var sub = document.getElementById("submit");
  15. var msg = document.getElementById("msg")
  16. sub.addEventListener("click",function(){
  17. ws.send(msg.value);
  18. });
  19. ws.addEventListener("open",function(){
  20. alert("WebSocket has been opened!");
  21. })
  22. }
  23. </script>
  24. </html>

这些为前端代码:实现了一个简单输入框,输入后主动通过websocket发送给服务端,服务端那边会打印再console中

效果:

测试成功,每一次点击提交都会显示!

WebSocket开发在线聊天室

功能点

  1. 用户进入输入用户名可开始聊天
  2. 登入后提示当前在线用户
  3. 聊天内容会广播给聊天室其他在线用户
  4. 用户进入后提示xxx用户进入聊天室
  5. 用户关闭后提示xxx用户退出聊天室

package.json同上不变,具体设计逻辑参考另一篇博客,我用TCP API实现的聊天室程序http://www.cnblogs.com/devilyouwei/p/8423961.html

前端:index.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>测试</title>
  6. <style>
  7. #inchat{
  8. display:none;
  9. }
  10. ul{
  11. list-style-type:none;
  12. }
  13. </style>
  14. </head>
  15. <body>
  16. <div id="inputname">
  17. <input type="text" value="" id="msg" placeholder="输入一个聊天昵称">
  18. <button id="submit">提交</button>
  19. </div>
  20. <div id="inchat">
  21. <ul id="chat-content">
  22. </ul>
  23. <textarea id="sendContent" value="">
  24. </textarea>
  25. <button id="send">发送</button>
  26. </div>
  27. </body>
  28. <script>
  29. window.onload=function(){
  30. var ws = new WebSocket('ws://localhost/ws');//需要修改为相应地址
  31. var sub = document.getElementById("submit");
  32. var msg = document.getElementById("msg")
  33. var ul = document.getElementById("chat-content");
  34. var send = document.getElementById("send");
  35. var sendContent = document.getElementById("sendContent");
  36. sendContent.value="";
  37. sub.addEventListener("click",function(){
  38. ws.send(msg.value);
  39. });
  40. send.addEventListener("click",function(){
  41. ws.send(sendContent.value);
  42. sendContent.value=""
  43. });
  44. ws.addEventListener("open",function(){
  45. alert("WebSocket has been opened!");
  46. })
  47. ws.addEventListener("message",function(e){
  48. var res = JSON.parse(e.data);
  49. //如果正在聊天中
  50. if(res.ischat){
  51. var li = document.createElement("li");
  52. li.innerText = res.info;
  53. ul.appendChild(li);
  54. }else{
  55. if(res.status == 1){
  56. document.getElementById("inputname").style.display="none";
  57. document.getElementById("inchat").style.display="block";
  58. }else{
  59. alert(res.info);
  60. }
  61. }
  62. });
  63. }
  64. </script>
  65. </html>

注意:放到公网访问需要把localhost改成ip或者网址!

后端:index.js

  1. var express = require("express");
  2. //创建express下的http服务
  3. var app = express();
  4. //关联express-ws中间件
  5. var expressWs = require("express-ws")(app);
  6. var users = {};
  7. var count = 0;
  8. //express托管静态文件
  9. app.use(express.static(__dirname+'/views',{'index':'index.html'}));
  10. //用ws方法而不是use方法
  11. app.ws('/ws',function(ws,req){
  12. var username = null;
  13. ws.on('message',function(msg){
  14. if(!username){
  15. if(users[msg]){
  16. ws.send(JSON.stringify({status:0,info:"用户名重复请重试",ischat:false}));
  17. }else if(msg == ""){
  18. ws.send(JSON.stringify({status:0,info:"用户名不能为空",ischat:false}));
  19. }else{
  20. username = msg;
  21. count++; //用户+1
  22. users[msg] = ws;
  23. ws.send(JSON.stringify({status:1,info:"注册成功,欢迎"+username,ischat:false}));
  24. console.log(username+"用户加入聊天室!当前在线:"+count);
  25. broadcast(username+"用户加入聊天室!当前在线:"+count);
  26. }
  27. }else{
  28. broadcast(username+":"+msg);
  29. console.log(username+":"+msg);
  30. }
  31. });
  32. ws.on('close',function(){
  33. delete users[username];
  34. count--;
  35. console.log(username+"用户退出聊天室!当前在线:"+count);
  36. broadcast(username+"用户退出聊天室!当前在线:"+count);
  37. })
  38. });;
  39. app.listen(80);
  40. //需要广播给所有人(不排除自己)
  41. function broadcast(msg){
  42. for(var i in users)
  43. users[i].send(JSON.stringify({status:1,info:msg,ischat:true}));
  44. }

注意1:express-ws中的ws.send()方法只能发送字符串,并没有express http的res.send()那么强大,故而我在传入js对象时,手动使用JSON.stringify()将对象转换为json字符串,待前端收到后再使用JSON.parse()转换回js对象。

注意2:WebSocket API中几个最重要的事件:open,close,message,error,对应了连接过程中的打开连接,关闭连接,消息传递,错误事件,无论前端还是后端都需要对这几个事件进行绑定监听,传入回掉函数做必要的处理

注意3:设计逻辑再讲一遍:users变量存储每一个连接引用,username作为局部变量,再每一次连接域内部,每一个客户端连入都会创建一个,单独的broadcast()方法遍历所有socket连接发送消息,最后再提醒一遍node.js开发一定要特别注意作用域范围!

效果

将js进行到底:node学习7的更多相关文章

  1. 【特别推荐】Node.js 入门教程和学习资源汇总

    这篇文章与大家分享一批很有用的 Node.js 入门教程和学习资源.Node 是一个服务器端的 JavaScript 解释器,它将改变服务器应该如何工作的概念.它的目标是帮助程序员构建高度可伸缩的应用 ...

  2. Node.js 入门教程和学习资源汇总

    这篇文章与大家分享一批很有用的 Node.js 入门教程和学习资源.Node 是一个服务器端的 JavaScript 解释器,它将改变服务器应该如何工作的概念.它的目标是帮助程序员构建高度可伸缩的应用 ...

  3. Node.js环境搭建和学习(windwos环境)

    Node.js环境搭建和学习 一.环境搭建 1.下载安装文件 下载地址http://nodejs-org.qiniudn.com/下载Node.js环境安装包,根据操作系统下载对应的安装包 下载地址 ...

  4. node 学习笔记 - Modules 模块加载系统 (1)

    本文同步自我的个人博客:http://www.52cik.com/2015/12/11/learn-node-modules-path.html 用了这么久的 require,但却没有系统的学习过 n ...

  5. [学姿势]实验室搬砖+node学习

    这周开始进行收尾工作,我当然没有进行核心技术的开发,主要负责的是对web端进行展示上的修修补补,主要包括添加VLC播放器.rtsp视频流以及一些js细节. 1.VLC 全称为Video Lan Cli ...

  6. 2015第40周二Node学习

    node历史 今天看cnode开源项目用了io.js,在查这个项目时发现这篇文章node历史,node.js和io.js关系谈到Node.js的由来,不可避免要聊到它的创始人Ryan Dahl.在20 ...

  7. 2015第40周一Node学习

    node学习尝试 早上看了张丹大牛博客文章nodeJS学习路线图和node从零入门系列,感觉获益匪浅,尝试了里面几项内容,对node有了更深入的认识. npm npm是一个node包管理和分发工具,已 ...

  8. Node学习——开篇

    前言:自从下决心转学前端以来,我的专业课java基本荒废了,所以对于后台开发的逻辑也已基本忘干净了.但是作为一名准前端程序猿,我认为还是有必要了解后端开发的,虽不必深入学习,但是能够了解项目从前端到后 ...

  9. node 学习资料

    Node 学习资料: 资料名称 网址 Node.js 中文API文档 http://nodejs.cn/api/ Node 菜鸟教程 http://www.runoob.com/nodejs/node ...

  10. Node学习HTTP模块(HTTP 服务器与客户端)

    Node学习HTTP模块(HTTP 服务器与客户端) Node.js 标准库提供了 http 模块,其中封装了一个高效的 HTTP 服务器和一个简易的HTTP 客户端.http.Server 是一个基 ...

随机推荐

  1. UML-如何画SSD?

    1.SSD来自哪里?答:用例文本 2.如何为系统事件和操作命名? 3.SSD中的哪些需要放到词汇表中? SSD元素包含 1).操作名称 2).参数 3).返回数据 这些元素,必须要简洁.但别人可能不太 ...

  2. python编程:从入门到实践----第六章:字典>练习

    6-1 人:使用一个字典来存储一个熟人的信息,包括名.姓.年龄和居住的城市.该字典应包含键first_name .last_name .age 和city .将存储在该字典中的每项信息都打印出来. f ...

  3. Java之线程通信的应用:经典例题:生产者/消费者问题

    /** * 线程通信的应用:经典例题:生产者/消费者问题 * * 生产者(Productor)将产品交给店员(Clerk),而消费者(Customer)从店员处取走产品, * 店员一次只能持有固定数量 ...

  4. Spring--Spring 注入

    Spring 提供了三种主要的装配机制: 在 XML 中进行显式配置 在 Java 中进行显式配置 隐式的 bean 发现机制和自动装配 Spring 从两个角度来实现自动化装配: 组件扫描:Spri ...

  5. Rails render collection 的魔法

    都知道的, 在 Rails 的 View 里边渲染集合的时候, 会用到 render 方法参数的 collection 选项 1 <%= render partial: "produc ...

  6. winEdt 使用

    晚上摘抄的方法: 1.点选Options -> Options Interface 2.右边会跳出一个介面,点选Advance Configuration... -> Event Hand ...

  7. 天融信(NAT)地址转换端口映射配置

    目的地址为公司的公网地址 服务:选择或者自己定义一个端口号,就是要映射到服务器上的那个端口号 目的地址转换为:服务器ip 目的端口转换为:选择定义的服务(端口号) 规则描述:随便写

  8. UML-业务规则

    样例:

  9. VS2010无法调试页面问题

    图片: VS2010报:未能将脚本调试器附加到计算机XXX上的进程iexplore.exe . 已附加了一个调试器”.启动调试失败. 解决:1.以管理员身份打开CMD; 2.运行:regsvr32.e ...

  10. 程序员计算器HEX、EDC、OCT等等的意思

    binary 二进制 对应的是 BINoctal 八进制的  ----   OCThexadecimal 十六进制的  --- HEXdecimal 十进制的  -- DEC