nodeJS+express+Jade写一个局域网聊天应用(node基础)
为了复习一下nodeJS, 而且socketIO这东西听起来就好高端有木有, 而且有人写过了open, 也可以作为自己的参考有木有, 点击下载源代码;
express是4.x的版本, 跟以前的配置有些区别, 我才不管呢, 好用就好>﹏<;
按照正常的流程通过 node install 安装项目依赖, 项目的依赖如下;
"dependencies": { "body-parser": "~1.8.4", "cookie-parser": "~1.3.3", "debug": "~2.0.0", "express": "~4.9.8", "jade": "~1.6.0", "morgan": "~1.3.2", "serve-favicon": "~2.1.7", "socket.io": "~1.2.1" }
(如果你像自己建项目的话 直接在命令行下 执行express projectName, express就会为你自动新建一个项目;)
先来看下高大上的服务端截图;
酷炫的客户端截图:
客户端的主要功能是发送消息, 如果用户不输入名字后台会分配一个名字给客户端;
服务端的主要功能是处理用户发送的数据, 然后把数据保存到json, 同时再把当前的新数据推送到所有 , 有连接到当前socket服务器的客户端;
简单的服务端流程如下:
//获取对应的依赖 var express = require('express'); var path = require('path'); var favicon = require('serve-favicon'); var logger = require('morgan'); var cookieParser = require('cookie-parser'); var bodyParser = require('body-parser'); var http = require("http"); //主要就是通过socketIO的实现消息的实时推送; var socketIo = require("socket.io"); //原生fileSystem模块,把数据保存起来的和获取数据用的; var fs = require("fs"); .... var app = express(); var server = http.createServer(app); //把socketIO绑定到服务上; io = socketIo( server ); io.on('connection', function (socket) { //socket的各种事件写在这边; }) //启动服务, 监听的端口设置在3000; server.listen( 3000 , function() { console.log(" server is created "); }); //使用jade模板, 以及设定视图目录; app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'jade');
服务端里面使用了封装了一个fs进行简单的文件操作,包括读取和写入的方法, 为了保存数据用的;
socket主要的几个事件要知道,包括:
//这个是socketIO初始化时候的事件; io.on('connection', function (socket) { //客户端发送 message给服务端的时候的事件, 用户发送过消息这个会触发; socket.on('message', function(msg){}); socket.on('disconnect', function (msg) {}); //给当前连接的客户端回传一条消息; socket.emit("message",{}); //给非当前的所有用户发送推送消息; socket.broadcast.emit("message",{}); //你可以给客户端发送各种事件,名字你找自己起; socket.emit('open',"sb"); socket.emit('hehe',"sb"); socket.emit('cnblogs',"sb"); });
所有的服务端代码(app.js)
var express = require('express'); var path = require('path'); var favicon = require('serve-favicon'); var logger = require('morgan'); var cookieParser = require('cookie-parser'); var bodyParser = require('body-parser'); var http = require("http"); var socketIo = require("socket.io"); var fs = require("fs"); var routes = require('./routes/index'); //var users = require('./routes/users'); var app = express(); // view engine setup app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'jade'); // uncomment after placing your favicon in /public //app.use(favicon(__dirname + '/public/favicon.ico')); //app.use('port', process.env.PORT || 3000); app.use(logger('dev')); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false })); app.use(cookieParser()); app.use(express.static(path.join(__dirname, 'public'))); app.use('/', routes); //app.use('/users', users); // catch 404 and forward to error handler app.use(function(req, res, next) { var err = new Error('Not Found'); err.status = 404; next(err); }); // development error handler // will print stacktrace if (app.get('env') === 'development') { app.use(function(err, req, res, next) { res.status(err.status || 500); res.render('error', { message: err.message, error: err }); }); }; // production error handler // no stacktraces leaked to user app.use(function(err, req, res, next) { res.status(err.status || 500); res.render('error', { message: err.message, error: {} }); }); var server = http.createServer(app); /* var server = http.createServer(function(req, res){ res.end("hehe"); }); */ io = socketIo( server ); var clients = {}; var appUtil = require("util")._extend({},{ getRandomId : function() { var i=0; i++; return function() { return "name"+(i++); } }(), read : function( callback ) { /* * data.json保存的数据结构为 { key:[] Array }; * */ fs.readFile("data/data.json",function(err,data){ data = data.toString(); callback( JSON.parse(data).key ); }); }, write : function( writeData ,callback ) { //读取数据并重写数据; this.read(function(data) { //我这个node读取单个json会返回一个a字符串,我就笑了,什么情况 // 如果你直接把json放在数组里面就没有这个问题; //data = data[0] === "a" ? data.slice(1) : data; data.push( writeData ); var temp = { key : data }; fs.writeFileSync("data/data.json",JSON.stringify(temp)); callback() }); } }); /* * @desc WebSocket API, 端口3000, msg为对象: * @param { } 传递空对象会返回 {msg : 读取文件的结果 JSON, name : 随机的一个name}; * @param { name : "xx" , type : "get" , msg : string }; //msg 读取文件的结果, type获取的类型 * @param { name : "xx" , type : "add" , msg : string }; //type 是 add为 添加, msg是指要添加的消息; */ io.on('connection', function (socket) { socket.emit('open',"laile");//通知客户端已连接 // 这个闭包内的工具方法; var sendMessage = function(name) { appUtil.read(function(data) { //给当前连接的用户发送sock消息 socket.emit("message",{ name : name, msg : data }); //给非当前的所有用户发送消息; socket.broadcast.emit("message",{ name : name, msg : data }); }); }; socket.on('message', function(msg){ console.log("来消息了"); console.log(msg); //如果是没有name的,我们会分配一条name给用户; var name = msg.name || appUtil.getRandomId(); if(!msg.name) { sendMessage( name ); clients[name] = true; }else if(msg.type == "get") { sendMessage(name); }else if( msg.type == "add" ) { //我勒个去,因为readFile和appendFile是异步的, 所以要添加回调, 当然, 你可以用同步的readFileSync; appUtil.write({ time : new Date().toString(), "name" : msg.name, "msg" : msg.msg}, function(){ sendMessage(name); }); }; //如果是新用户的话, 广播一条叫做新用户登陆的信息; console.log(name) if(!clients[name]) { clients[name] = true; console.log("广播新用户登录的消息"); //注意 : 这个是socket,不是msg; socket.broadcast.emit("refreshUser",name); }; }); socket.on('disconnect', function (msg) {}); }); server.listen( 3000 , function() { console.log(" server is created "); }); module.exports = app;
客户端的代码你要引用socket.io模块下的socket.io/socket.io.js, 你通过 new WebSocket("ws://127.0.0.1") 一直会提示错误, 错误消息如下:
WebSocket connection to 'ws://127.0.0.1/' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED
然后通过socket.io这个库给我们提供的方法进行连接(我也不知道为什么这个可以连接,使用new WebSocket反正是连接不了):
var ws = io.connect('http://localhost:3000');
客户端的代码如下:
var ws = null; var name = ""; var Ws = function(url) { /* 只能说呵呵了, 使用new WebSocket无法连接到服务器, 提示握手前断开连接; if(!window.WebSocket) return null; var ws = new WebSocket( 'ws:' + window.location.href.substring(window.location.protocol.length) ); */ var ws = io.connect('http://localhost:3000'); ws.on('open',function(data) { log(data); ws.send({}); }); ws.on("refreshUser", function(msg){ $("<div></div>").html( msg+"登陆了哇" ).appendTo( $("#users") ); }); // socketIo连接开始握手的消息在chrome开发工具的请求中可以看到, // 握手以后的消息传送无法截取; ws.on("message", function(data) { $("#output").html(" "); name = data.name; $("#name").val(data.name); var arr = data.msg; while( s = arr.shift() ) { log( s ); }; window.scrollTo(0, 100000); }); var sendMessage = function(msg){ ws.send(msg); }; return ws; function log(s,e) { var output = document.getElementById("output"); var p = document.createElement("p"); p.style.wordWrap = "break-word"; p.style.padding="10px"; p.style.background="#eee"; p.innerHTML = s.name + " at " + (new Date(s.time)).toDateString() + " :<br>==>> <b>"+ s.msg +"</b>"; output.appendChild(p); }; }; function init() { ws = Ws(); if(ws === null) { alert("不支持webSocket!"); }; $("#ipt").keydown(function(e) { var e = e || window.event; if (e.keyCode === 13) { var msg = $(this).val(); if (!msg) return; ws.send({ type : "add", msg : msg, name : $("#name").val() }); $(this).val(''); }; }); }; window.onload = init;
jade这个模板和express的路由什么的就不说了, 自己写个两行就懂了, 教程那么多, imooc屌炸天是不是哇, 明天复习JAVASCRIPT搞基程序设计3, 你懂的;
捐给给钱,这个我的支付宝账号:mayun.taobao.com;