`

模块简单设计——socket.io聊天代码

 
阅读更多

参照网上的各种教程和代码实现一个简易在线聊天器,支持定向发消息

服务器端

app.js(使用express搭建静态服务,socket.io建立服务器端监听)

 

var app = require('express')()
, express = require('express')
, server = require('http').createServer(app)
, io = require('socket.io').listen(server);

var zTool = require("./zTool");
var onlineUserMap = new zTool.SimpleMap();
var historyContent = new zTool.CircleList(100);

EVENT_TYPE = {
	"LOGIN":"LOGIN",
	"LOGOUT":"LOGOUT",
	"CHAT":"CHAT",
	"ERROR":"ERROR"
};

server.listen(80);

app.use('/', express.static(__dirname + '/'));

io.sockets.on('connection', function (socket){
		//
		// exception from clients
		//
		socket.on("disconnect", function (){
			var user = onlineUserMap.get(socket.id);
			var data = JSON.stringify({
				"event":EVENT_TYPE.LOGOUT,
				"values":[user]
				});
			onlineUserMap.remove(socket.id);
			io.sockets.emit("message",data);//broadcast
			});
		//
		// normal messages(login | logout | chat)
		//
		socket.on('message', function (message){
			//json decode
			var msgData = JSON.parse(message);

			if(msgData && msgData.event){
			switch(msgData.event) {
			//
			//user login
			//
			case EVENT_TYPE.LOGIN:
			var newUser = {"uid":socket.id, "nick":msgData.values[0]};
			onlineUserMap.put(socket.id, newUser);

			var data = JSON.stringify({
				"user":onlineUserMap.get(socket.id),
				"event":EVENT_TYPE.LOGIN,
				"values":[newUser],
				"users":onlineUserMap.values(),
				"historyContent":historyContent.values()
				});
			io.sockets.emit("message",data);//broadcast
			break;
			//
			//user chat
			//
			case EVENT_TYPE.CHAT:
			var content = msgData.values[0];
			var data = JSON.stringify({
					"user":onlineUserMap.get(socket.id),
					"event":EVENT_TYPE.CHAT,
					"values":[content]
					});

			var to = msgData.to;
			if(to != 0){//private chat
				io.sockets.emit(socket.id,data); //to sender
				io.sockets.emit(to,data);//to receiver
			}
			else{//public chat
				io.sockets.emit("message",data);//broadcast
				historyContent.add({
						"user":onlineUserMap.get(socket.id),
						"content":content,
						"time":new Date().getTime()
						});
			}
			break;
			//
			//user logout
			//
			case EVENT_TYPE.LOGOUT:
			var user = msgData.values[0];
			onlineUserMap.remove(user.uid);
			var data = JSON.stringify({
					"event":EVENT_TYPE.LOGOUT,
					"values":[user]
					});
			io.sockets.emit("message",data);//broadcast
			break; 
			}
			} else {
				console.log("invalid message , userId:"+socket.id+" , message:"+message);
				var data = JSON.stringify({
						"uid":socket.id,
						"event":EVENT_TYPE.ERROR
						});
				socket.emit(socket.id, data);
			}
		});
});

网页端index.html

 

<html>
<head>
	<title>chatroom</title>
	<meta charset="utf-8" />
	<script src="jquery.js"></script>
	<script src="zTool.js"></script>
	<script src="DateUtil.js"></script>
	<script src="chat.js"></script>
	<script src="http://127.0.0.1:80/socket.io/socket.io.js"></script>
	<link href="style.css" rel="stylesheet" media="all">
</head>
<body>

<div id="errorPage" class="page" style="display:none">
	<h1>当前浏览器不支持WebSocket,请使用其他浏览器,例如chrome 4.0.249.0 +</h1>
</div>

<div id="prePage" class="page" style="text-align:center;">
	<input id = "nickInput" type="text" class="itext" placeholder="输入昵称" style="margin-top:150px;" />
	<input id = "enter" type="button" class="ibutton" value="开始聊天" />
</div>
<div id="mainPage" class="page" style="display:none">
	<div>
		<div class="talkLeft">
			<div id="talkFrame" class="talkHistory">
			</div>
		</div>
		<div class="talkRight">
			<div id="onlineUsers"></div>
		</div>
	</div>
	<div id="inputDiv" style="margin-top:50px">
		<input placeholder="说点什么" id="message" class="itext" />
		<input type="button" class="ibutton" value="发送" id="send" />
		<input type="button" class="ibutton" value="退出" id="logout" />
		<select style="float:right" id="chatWith" class="iselect">
			<option>所有人</option>
		</select>
	</div>
</div>
</body>
</html>

 网页端chat.js(监听各种消息,监听服务器异常断开等)

 

EVENT_TYPE = {
	"LOGIN":"LOGIN",
	"LOGOUT":"LOGOUT",
	"CHAT":"CHAT",
	"ERROR":"ERROR"
};

$(document).ready(function() {

		var socket = null;
		var onlineUserMap = new zTool.SimpleMap();
		var currentUser = null;
		var currentUserNick = null;

		if (typeof WebSocket === 'undefined') {
		$("#prePage").hide();
		$("#errorPage").show();
		}

		function appendMessage(msg) {
		$("#talkFrame").append("<div>" + msg + "</div>");
		document.getElementById("talkFrame").scrollTop = document.getElementById("talkFrame").scrollHeight;
		}	

		function formatUserTalkString(user) {
			return user.nick + "  " + new Date().format("hh:mm:ss") + " ";
		}

		function formatUserTalkHisString(user, time) {
			return user.nick + "  " + new Date(time).format("yyyy-MM-dd hh:mm:ss") + " ";
		}

		function reset() {
			if (socket) {
				socket.close();
			}
			socket = null;
			onlineUserMap = null;
			currentUser = null;
			$("#onlineUsers").html("");
			$("#talkFrame").html("");
			$("#nickInput").val("");
			$("#chatWith").val("<option>所有人</option>");
		}

		function setChatWith(uid){
			$("#chatWith").find(uid).attr("SELECTED","SELECTED");
		}

		function updateOnlineUser() {
			var html = ["<div>在线用户(" + onlineUserMap.size() + ")</div>"];
			if (onlineUserMap.size() > 0) {
				var users = onlineUserMap.values();
				var number = users.length;
				for ( var i=0;i<number;i++) {
					html.push("<div>");
					if (users[i].uid == currentUser.uid) {
						html.push("<b>" + users[i].nick + "(我)</b>");
					} else {
						html.push(users[i].nick);
					}
					html.push("</div>");
				}
			}

			$("#onlineUsers").html(html.join(''));
		}

		function updateChatWith() {
			var html = ["<option value=\"0\">所有人</option>"];
			if (onlineUserMap.size() > 0) {
				var users = onlineUserMap.values();
				var number = users.length;
				for ( var i=0;i<number;i++) {
					if (users[i].uid == currentUser.uid) {
					} else {
						html.push("<option value=\""+users[i].uid+"\">");
						html.push(users[i].nick);
						html.push("</option>");
					}
				}
			}

			$("#chatWith").html(html.join(''));
		}

		//enter chatroom
		$("#enter").click(function(event) {
				currentUserNick = $.trim($("#nickInput").val());
				if ('' == currentUserNick) {
				alert('请先输入昵称');
				return;
				}

				$("#prePage").hide();
				$("#mainPage").show();
				reset();

				socket = io.connect('http://127.0.0.1');
				onlineUserMap = new zTool.SimpleMap();
				socket.on('connect', function () {
					socket.emit('message', JSON.stringify({
							'event' : EVENT_TYPE.LOGIN,
							'values' : [currentUserNick]
							}));
					});

				socket.on("disconnect",function(message){
					$("#prePage").show();
					$("#mainPage").hide();
					close();
					});

				socket.on("message",function(message){
						var mData = JSON.parse(message);
						if (mData && mData.event) {
						switch (mData.event) {
						//
						// user login
						//
						case EVENT_TYPE.LOGIN:
						var user = mData.values[0];
						var users = mData.users;
						if (users && users.length) {
						var number = users.length;
						for (var i=0;i<number;i++) {
						onlineUserMap.put(users[i].uid, users[i]);
						if (mData.user.uid == users[i].uid && currentUser == null) {
						currentUser = users[i];
						//
						// listen on private chat
						//
						socket.on(currentUser.uid,function(pmessage){
							var pmData = JSON.parse(pmessage);
							if (pmData && pmData.event) {
							switch (pmData.event) {
							case EVENT_TYPE.CHAT:
							var content = pmData.values[0];
							appendMessage(formatUserTalkString(pmData.user));
							appendMessage("<span>&nbsp;&nbsp;</span>" + content);
							break;
							}
							}
							});
						}
						}
						}
						//
						// get history message
						//
						var data = mData.historyContent;

						if (data && data.length) {
							var number = data.length;
							for ( var i=0;i<number;i++) {
								appendMessage(formatUserTalkHisString(data[i].user, data[i].time));
								appendMessage("<span>&nbsp;&nbsp;</span>" + data[i].content);
							}
							appendMessage("<span class='gray'>==================以上为最近的历史消息==================</span>");
						}

						updateOnlineUser();
						updateChatWith();
						appendMessage(formatUserTalkString(user) + "[进入房间]");
						break;

						//
						// user logout
						//
						case EVENT_TYPE.LOGOUT: 
						var user = mData.values[0];
						onlineUserMap.remove(user.uid);
						updateOnlineUser();
						updateChatWith();
						appendMessage(formatUserTalkString(user) + "[离开房间]");
						break;

						//
						// user public chat
						//
						case EVENT_TYPE.CHAT:
						var content = mData.values[0];
						appendMessage(formatUserTalkString(mData.user));
						appendMessage("<span>&nbsp;&nbsp;</span>" + content);
						break;

						case EVENT_TYPE.ERROR:
						appendMessage("[error state...]");
						break;

						default:
						break;
						}

						}

				});

				socket.on("error",function(){
						appendMessage("[server encounts an error...]");
						});


				socket.on("close",function(){
						appendMessage("[server is closed...]");
						close();
						});

		});


		//send a message
		$("#send").click(function(event) {
				var value = $.trim($("#message").val());
				var to = $.trim($("#chatWith").val());
				if (value) {
				$("#message").val('');
				var data = JSON.stringify({
					'event' : EVENT_TYPE.CHAT,
					'to' : to,
					'values' : [value]
					});
				socket.emit('message',data);
				}
				});

		//logout
		$("#logout").click(function(event){
				var data = JSON.stringify({
					'event' : EVENT_TYPE.LOGOUT,
					'values' : [currentUser]
					});
				socket.emit('message',data);
				$("#prePage").show();
				$("#mainPage").hide();
				});
});

 运行方式sudo node app.js

附:zTool.js如下

(function (exports) {
	var SimpleMap = exports.SimpleMap = function() {
		this.map = {};
		this.mapSize = 0;
	};

	SimpleMap.prototype.put = function(key, value) {
		var oldValue = this.map[key];
		this.map[key] = value;
		if (!oldValue) {
			this.mapSize++;
		}
		return (oldValue || value);
	};

	SimpleMap.prototype.get = function(key) {
		return this.map[key];
	};

	SimpleMap.prototype.remove = function(key) {
		var v = this.map[key];
		if (v) {
			delete this.map[key];
			this.mapSize--;
		};
		return v;
	};

	SimpleMap.prototype.size = function() {
		return this.mapSize;
	};

	SimpleMap.prototype.clear = function() {
		this.map = {};
		this.mapSize = 0;
	};

	SimpleMap.prototype.keySet = function() {
		var theKeySet = [];
		for (var i in this.map) {
			theKeySet.push(i);
		}
		return theKeySet;
	};

	SimpleMap.prototype.values = function() {
		var theValue = [];
		for (var i in this.map) {
			theValue.push(this.map[i]);
		}
		return theValue;
	};

	var CircleList = exports.CircleList = function(maxSize) {
		this.maxSize = (maxSize || 10);
		this.list = [];
		this.index = null;
	};

	CircleList.prototype.clear = function() {
		this.list = [];
		this.index = null;
	};

	CircleList.prototype.add = function(value) {
		if (null == this.index) {
			this.index = 0;
		}

		this.list[this.index++] = value;
		
		if (this.index == this.maxSize) {
			this.index = 0;
		}
	};

	CircleList.prototype.values = function() {
		var theValue = [];
		if (null != this.index) {
			if (this.list.length == this.maxSize) {
				for (var i = this.index; i < this.maxSize; i++) {
					theValue.push(this.list[i]);
				}
			}

			for (var i = 0; i < this.index; i++) {
				theValue.push(this.list[i]);
			}
		}
		return theValue;
	};

})( (function(){
    if(typeof exports === 'undefined') {
        window.zTool = {};
        return window.zTool;
    } else {
        return exports;
    }
})() );

 

分享到:
评论
2 楼 sunshine217 2014-03-25  
请问 var zTool = require("./zTool");  ,这句中的zTool.js是什么,上哪去下载呢?起什么作用呢?
1 楼 fgjun 2014-02-28  
代码中的
io.sockets.emit(socket.id,data); //to sender 
io.sockets.emit(to,data);//to receiver 
可以参考下面的方式
// sending to individual socketid
io.sockets.socket(socketid).emit('message', 'for your eyes only');
参考网址:
https://github.com/LearnBoost/socket.io/wiki/How-do-I-send-a-response-to-all-clients-except-sender%3F

相关推荐

    node.js利用socket.io实现多人在线匹配联机五子棋

    server端使用node的socket.io模块与客户端进行数据交互,棋子的落点和输赢校验均是在server端完成。 五子棋ui界面请见.. client端的界面这里就不做过多解释了,只要稍微懂点h5就可以自行去这里 下载源代码观看,...

    Node.js Web开发实战-(共14章)PPT.rar

    第1章 初识 Node.js.ppt 第2章 Javascript基础.ppt 第3章 Node.js基础入门.ppt ...第11章 socket.io 模块.ppt 第12章 MongoDb数据库.ppt 第13章 综合项目——全栈开发博客网.ppt 第14章 课程设计——网络版五子棋.ppt

    CmpE272_RFID_Project:CmpE 272 项目

    • 这将适用于电子板——连接到计算机的 RFID 阅读器。 智能读板机将访问植入食物中的信息。 人们将能够检查过敏原的成分,密切关注饮食并检查成分是否真实。 • 技术栈:NodeJS、JavaScript、Html、JQuery、Mysql...

    JAVA上百实例源码以及开源项目源代码

    简单聊天软件CS模式 2个目标文件 一个简单的CS模式的聊天软件,用socket实现,比较简单。 凯撒加密解密程序 1个目标文件 1、程序结构化,用函数分别实现 2、对文件的加密,解密输出到文件 利用随机函数抽取幸运数字 ...

    基于VS2019 C++的跨平台(Linux)开发的项目——360 度智能行车辅助系统

    基于 Socket 网络通讯技术,使用Qt5进行GUI编程,结合OpenCV图像处理,采用Sqlite3数据库,实现的 360 度智能...项目核心技术点 :服务器分离、共享内存设计、线程池、Socket网络编程、进程间通信、epoll多路IO复用等。

    java源码包---java 源码 大量 实例

    Java Socket 聊天通信演示代码 2个目标文件,一个服务器,一个客户端。 Java Telnet客户端实例源码 一个目标文件,演示Socket的使用。 Java 组播组中发送和接受数据实例 3个目标文件。 Java读写文本文件的示例...

    JAVA上百实例源码以及开源项目

    一个简单的CS模式的聊天软件,用socket实现,比较简单。 凯撒加密解密程序 1个目标文件 1、程序结构化,用函数分别实现 2、对文件的加密,解密输出到文件 利用随机函数抽取幸运数字 简单 EJB的真实世界模型(源代码...

    java源码包2

    Java Socket 聊天通信演示代码 2个目标文件,一个服务器,一个客户端。 Java Telnet客户端实例源码 一个目标文件,演示Socket的使用。 Java 组播组中发送和接受数据实例 3个目标文件。 Java读写文本文件的示例...

    java源码包3

    Java Socket 聊天通信演示代码 2个目标文件,一个服务器,一个客户端。 Java Telnet客户端实例源码 一个目标文件,演示Socket的使用。 Java 组播组中发送和接受数据实例 3个目标文件。 Java读写文本文件的示例...

    java源码包4

    Java Socket 聊天通信演示代码 2个目标文件,一个服务器,一个客户端。 Java Telnet客户端实例源码 一个目标文件,演示Socket的使用。 Java 组播组中发送和接受数据实例 3个目标文件。 Java读写文本文件的示例...

    成百上千个Java 源码DEMO 4(1-4是独立压缩包)

    简单聊天软件CS模式 2个目标文件 一个简单的CS模式的聊天软件,用socket实现,比较简单。 凯撒加密解密程序 1个目标文件 1、程序结构化,用函数分别实现 2、对文件的加密,解密输出到文件 利用随机函数抽取幸运数字 ...

    成百上千个Java 源码DEMO 3(1-4是独立压缩包)

    简单聊天软件CS模式 2个目标文件 一个简单的CS模式的聊天软件,用socket实现,比较简单。 凯撒加密解密程序 1个目标文件 1、程序结构化,用函数分别实现 2、对文件的加密,解密输出到文件 利用随机函数抽取幸运数字 ...

    Linux高性能服务器编程

    聊天室程序 9.6.1 客户端 9.6.2 服务器 9.7 IO复用的高级应用三:同时处理TCP和UDP服务 9.8 超级服务xinetd 9.8.1 xinetd配置文件 9.8.2 xinetd工作流程 第10章 信号 10.1 Linux信号概述 10.1.1 发送信号 ...

Global site tag (gtag.js) - Google Analytics