為了復習一下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;