将js进行到底:node学习7
Node.js之Websocket技术
我第一次听说websocket之时,HTML5标准尚未公布,当时只有少数前瞻性浏览器携带了这个API。
我对websocket最大的印象是,他可以解决我对“在线聊天系统”开发的疑惑(我一直想不通http如何保持长连接),这样我们无需使用轮询ajax和php无限循环去模拟,还记得2014年初那会我写了一个在线聊天室,那时候我真的应该用websocket技术的,php无限轮询的方式,只要3-4个人在线就可以让linux+apache服务器崩溃。
很可惜,我没有在php上使用过Websocket API,今天是我第一次将这个技术用来实践,使用node.js实现
引入模块
package.json
{
"name":"chat-websocket",
"version":"0.0.1",
"description":"use websocket to create a char server",
"dependencies":{
"express":"latest",
"express-ws":"latest"
}
}
在引入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
var express = require("express");
//创建express下的http服务
var app = express();
//关联express-ws中间件
var expressWs = require("express-ws")(app);
//express托管静态文件
app.use(express.static(__dirname+'/views',{'index':'index.html'}));
app.ws('/ws',function(ws,req){
ws.on('message',function(msg){
console.log(msg);
})
});;
app.listen(80);
这个index.js是服务端代码
解析:
- 先引入express模块,并使用express()方法获得app对象
- 引入express-ws并构造对象,构造函数传入的是app对象,意思大概是绑定到express服务器上
- 通常接受http请求使用的是app.use(),而websocket请求则使用app.ws(),该方法就是中间件扩展的
- message事件监听客户端发送的数据,并打印到终端上
views/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>测试</title>
</head>
<body>
<input type="text" value="" id="msg">
<button id="submit">提交</button>
</body>
<script>
window.onload=function(){
var ws = new WebSocket('ws://localhost/ws')
var sub = document.getElementById("submit");
var msg = document.getElementById("msg")
sub.addEventListener("click",function(){
ws.send(msg.value);
});
ws.addEventListener("open",function(){
alert("WebSocket has been opened!");
})
}
</script>
</html>
这些为前端代码:实现了一个简单输入框,输入后主动通过websocket发送给服务端,服务端那边会打印再console中
效果:
测试成功,每一次点击提交都会显示!
WebSocket开发在线聊天室
功能点
- 用户进入输入用户名可开始聊天
- 登入后提示当前在线用户
- 聊天内容会广播给聊天室其他在线用户
- 用户进入后提示xxx用户进入聊天室
- 用户关闭后提示xxx用户退出聊天室
package.json同上不变,具体设计逻辑参考另一篇博客,我用TCP API实现的聊天室程序http://www.cnblogs.com/devilyouwei/p/8423961.html
前端:index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>测试</title>
<style>
#inchat{
display:none;
}
ul{
list-style-type:none;
}
</style>
</head>
<body>
<div id="inputname">
<input type="text" value="" id="msg" placeholder="输入一个聊天昵称">
<button id="submit">提交</button>
</div>
<div id="inchat">
<ul id="chat-content">
</ul>
<textarea id="sendContent" value="">
</textarea>
<button id="send">发送</button>
</div>
</body>
<script>
window.onload=function(){
var ws = new WebSocket('ws://localhost/ws');//需要修改为相应地址
var sub = document.getElementById("submit");
var msg = document.getElementById("msg")
var ul = document.getElementById("chat-content");
var send = document.getElementById("send");
var sendContent = document.getElementById("sendContent");
sendContent.value="";
sub.addEventListener("click",function(){
ws.send(msg.value);
});
send.addEventListener("click",function(){
ws.send(sendContent.value);
sendContent.value=""
});
ws.addEventListener("open",function(){
alert("WebSocket has been opened!");
})
ws.addEventListener("message",function(e){
var res = JSON.parse(e.data);
//如果正在聊天中
if(res.ischat){
var li = document.createElement("li");
li.innerText = res.info;
ul.appendChild(li);
}else{
if(res.status == 1){
document.getElementById("inputname").style.display="none";
document.getElementById("inchat").style.display="block";
}else{
alert(res.info);
}
}
});
}
</script>
</html>
注意:放到公网访问需要把localhost改成ip或者网址!
后端:index.js
var express = require("express");
//创建express下的http服务
var app = express();
//关联express-ws中间件
var expressWs = require("express-ws")(app);
var users = {};
var count = 0;
//express托管静态文件
app.use(express.static(__dirname+'/views',{'index':'index.html'}));
//用ws方法而不是use方法
app.ws('/ws',function(ws,req){
var username = null;
ws.on('message',function(msg){
if(!username){
if(users[msg]){
ws.send(JSON.stringify({status:0,info:"用户名重复请重试",ischat:false}));
}else if(msg == ""){
ws.send(JSON.stringify({status:0,info:"用户名不能为空",ischat:false}));
}else{
username = msg;
count++; //用户+1
users[msg] = ws;
ws.send(JSON.stringify({status:1,info:"注册成功,欢迎"+username,ischat:false}));
console.log(username+"用户加入聊天室!当前在线:"+count);
broadcast(username+"用户加入聊天室!当前在线:"+count);
}
}else{
broadcast(username+":"+msg);
console.log(username+":"+msg);
}
});
ws.on('close',function(){
delete users[username];
count--;
console.log(username+"用户退出聊天室!当前在线:"+count);
broadcast(username+"用户退出聊天室!当前在线:"+count);
})
});;
app.listen(80);
//需要广播给所有人(不排除自己)
function broadcast(msg){
for(var i in users)
users[i].send(JSON.stringify({status:1,info:msg,ischat:true}));
}
注意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的更多相关文章
- 【特别推荐】Node.js 入门教程和学习资源汇总
这篇文章与大家分享一批很有用的 Node.js 入门教程和学习资源.Node 是一个服务器端的 JavaScript 解释器,它将改变服务器应该如何工作的概念.它的目标是帮助程序员构建高度可伸缩的应用 ...
- Node.js 入门教程和学习资源汇总
这篇文章与大家分享一批很有用的 Node.js 入门教程和学习资源.Node 是一个服务器端的 JavaScript 解释器,它将改变服务器应该如何工作的概念.它的目标是帮助程序员构建高度可伸缩的应用 ...
- Node.js环境搭建和学习(windwos环境)
Node.js环境搭建和学习 一.环境搭建 1.下载安装文件 下载地址http://nodejs-org.qiniudn.com/下载Node.js环境安装包,根据操作系统下载对应的安装包 下载地址 ...
- node 学习笔记 - Modules 模块加载系统 (1)
本文同步自我的个人博客:http://www.52cik.com/2015/12/11/learn-node-modules-path.html 用了这么久的 require,但却没有系统的学习过 n ...
- [学姿势]实验室搬砖+node学习
这周开始进行收尾工作,我当然没有进行核心技术的开发,主要负责的是对web端进行展示上的修修补补,主要包括添加VLC播放器.rtsp视频流以及一些js细节. 1.VLC 全称为Video Lan Cli ...
- 2015第40周二Node学习
node历史 今天看cnode开源项目用了io.js,在查这个项目时发现这篇文章node历史,node.js和io.js关系谈到Node.js的由来,不可避免要聊到它的创始人Ryan Dahl.在20 ...
- 2015第40周一Node学习
node学习尝试 早上看了张丹大牛博客文章nodeJS学习路线图和node从零入门系列,感觉获益匪浅,尝试了里面几项内容,对node有了更深入的认识. npm npm是一个node包管理和分发工具,已 ...
- Node学习——开篇
前言:自从下决心转学前端以来,我的专业课java基本荒废了,所以对于后台开发的逻辑也已基本忘干净了.但是作为一名准前端程序猿,我认为还是有必要了解后端开发的,虽不必深入学习,但是能够了解项目从前端到后 ...
- node 学习资料
Node 学习资料: 资料名称 网址 Node.js 中文API文档 http://nodejs.cn/api/ Node 菜鸟教程 http://www.runoob.com/nodejs/node ...
- Node学习HTTP模块(HTTP 服务器与客户端)
Node学习HTTP模块(HTTP 服务器与客户端) Node.js 标准库提供了 http 模块,其中封装了一个高效的 HTTP 服务器和一个简易的HTTP 客户端.http.Server 是一个基 ...
随机推荐
- java 利用管道实现线程间通信
package com.lb; import java.io.IOException;import java.io.PipedInputStream;import java.io.PipedOutpu ...
- sql plus笔记
指令请走这边 因为sql plus缓冲区有限 所以要查看输出有时会不太方便 使用spool语句将输出写入文件 sql>spool 要保存的完整路径 ; ; ; sql output; ; ; s ...
- 关于JavaWeb中Servlet的总结
Servlet知识结构图 Servlet是JavaWeb服务器端的程序,一般一个Servlet处理一种特定的请求.Servlet编写好后,需要指定其所处理的请求的请求路径,也可以认为Servlet是一 ...
- tensorflow C++接口调用目标检测pb模型代码
#include <iostream> #include "tensorflow/cc/ops/const_op.h" #include "tensorflo ...
- mysql 不停机 短时间锁表 备份 主备同步 新增备份机器
刷新数据 [root@localhost ~]# mysql -e 'flush tables with read lock;' 锁表刷新表数据 [root@localhost ~]# mys ...
- NOIp2017TG解题报告
NOIp2018RP++! 虽然没去但还得写写QAQ D1T1 : 小凯的疑惑 数学题 手推几组数据然后发现规律 \(Ans = (a-1)(b-1)+1\) AC in 1minite D1T2 : ...
- 【转】 java类的加载和执行顺序
1.先执行Test类的静态代码块后执行Test类的main方法,说明要执行类的方法需要先加载这个类. 2.在创建ClassB的对象时,先去加载了父类ClassA.说明加载子类时如果没有加载父类,会先加 ...
- 关于SG函数
Sprague-Grundy定理(SG定理): 游戏和的SG函数等于各个游戏SG函数的Nim和.这样就可以将每一个子游戏分而治之,从而简化了问题.而Bouton定理就是Sprague-Grundy定理 ...
- Python笔记_第四篇_高阶编程_GUI编程之Tkinter_5.鼠标事件
1. 鼠标点击事件: 图示: 实例: import tkinter from tkinter import ttk # 创建主窗口__编程头部 win = tkinter.Tk() # 设置标题 wi ...
- 题解-------CF372C Watching Fireworks is Fun
传送门 一道有趣的DP 题目大意 城镇中有$n$个位置,有$m$个烟花要放.第$i$个烟花放出的时间记为$t_{i}$,放出的位置记为$a_{i}$.如果烟花放出的时候,你处在位置$x$,那么你将收获 ...