HTML5——WebSocket:基于Node.js的网络聊天室

Day12

今日份内容:使用WebSocket制作基于Node.js的网络聊天室

WebSocket是一种基于TCP协议的通信技术,与传统HTTP有一定区别。

WebSocket

  • 了解WebSocket通信机制
  • 熟悉WebSocket API接口
  • 使用WebSocket技术实现双向通信
  • 了解Notification消息提醒机制

内容

  1. 配置Node.js环境
  2. 项目初始化
  3. 安装Express、WebSocket、node_uuid框架
  4. 服务端实现
  5. 客户端实现

代码

// index.js

var express = require('express');
const http = require('http');
const url = require('url');
const WebSocket = require('ws');
const uuid = require('node-uuid');
var app = express();
//下面会修改临时文件的存储位置
app.use(express.static('public'));
//设置http服务监听的端口号
app.set('port', process.env.PORT || 3000);
app.listen(app.get('port'), function() {
	console.log("Express started on localhost:" + app.get('port') + ':press Ctrl-C to terminate.');
});
//浏览器访问localhost会输出一个html文件
app.get('/', function(req, res) {
	res.type('text/html');
	res.sendFile('./index.html');
});
const server = http.createServer(app);
const wss = new WebSocket.Server({
	server
});
server.listen(8080, function listening() {
	console.log('Listening on %d', server.address().port);
});

var connections = [];
var userList = [];
var chatList = [];
var headImages = ["head1", "head2", "head3", "head4", "head5"];
wss.on('connection', function connection(ws, req) {
	var currentUser;
	var client_uuid = uuid.v4();
	connections.push({
		"id": client_uuid,
		"ws": ws
	});
	console.log('&&&&&client[%s]连接成功!&&&&&', client_uuid);
	//用户连接时,获得在线用户列表
	ws.send(getUsersOnLine());
	ws.on('message', function incoming(message) {
		let json = JSON.parse(message);
		//当用户发出登录请求时
		if (json.op == "login") {
			let userName = json.userName;
			let loginTime = new Date();
			let index = Math.ceil(Math.random() * (headImages.length));
			//封装登录用户信息,以便保存到WebSocket中
			currentUser = {
				'userName': userName,
				'loginTime': loginTime,
				'headImages': headImages[index]
			};
			userList.push({
				"id": client_uuid,
				"user": currentUser
			});
			console.log('########client[%s]登录成功########', currentUser);
			broadCast(getUsersOnLine());
			broadCastNotification(getNewUser(currentUser.userName), ws);
			//发送用户登录会话
			ws.send(getUserWithConnectionInfo(client_uuid));
		} else if (json.op = "chat") {
			let connectionId = json.connectionId;
			let chatMessage = json.chatMessage;
			let time = json.time;
			let user = getUserFromUserList(connectionId);
			let msg = {
				'user': user,
				'charMessage': charMessage,
				'time': time
			};
			chatList.push({
				"id": client_uuid,
				"msg": msg
			});
			broadCast(getAllMessage());
		}
	});
	ws.on('close', function() {
		for (var i in connections) {
			if (connections[i].ws == ws) {
				connections.pop(ws);
				break;
			}
		}
		if (currentUser != null && currentUser.userName != null) {
			userList.pop(currentUser);
			broadCastNotification(getUserOffLine(currentUser.userName), ws);
			broadCast(getUsersOnLine());
		}
		ws.close();
	});
});

function onLineList(message, ws) {
	ws.send(message);
}
//向客户端以数组形式发送在线用户列表
function broadCast(message) {
	for (var i in connections) {
		try {
			if (connections[i].ws.readyState === WebSocket.OPEN) {
				//参数为字符串类型
				connections[i].ws.send(Message);
			}
		} catch (e) {
			console.log(e);
			connections.pop(connections[i]);
		}
	}
}
//广播通知消息
function broadCastNotification(message, ws) {
	for (var i in connections) {
		try {
			if (connections[i].ws.readyState === WebSocket.OPEN && connections[i].ws != ws) {
				//参数为字符串类型
				connections[i].ws.send(message);
			}
		} catch (e) {
			//TODO handle the exception
			console.log(e);
			connections.pop(connections[i]);
		}
	}
}
//返回现在用户列表,并以字符串形式返回
function getUsersOnLine() {
	let jsonObject = {};
	jsonObject.users = userList;
	jsonObject.contentType = 'userOnLineList';
	return JSON.stringify(jsonObject);
}
//获得新用户上线信息,并以字符串形式返回
function getNewUser(userName) {
	let jsonObject = {};
	jsonObject.userName = userName;
	jsonObject.contentType = 'newUserOnLine';
	return JSON.stringify(jsonObject);
}
//封装离散用户
function getUserOffLine(userName) {
	let jsonObject = {};
	jsonObject.userName = userName;
	jsonObject.contentType = 'userOffLine';
	return JSON.stringify(jsonObject);
}
//返回指定的客户信息
function getUserWithConnectionInfo(connectionId) {
	let jsonObject = {};
	jsonObject.connectionId = connectionId;
	jsonObject.contentType = "userSession";
	return JSON.stringify(jsonObject);
}
//根据connectionId查找在线用户列表
function getUserFromUserList(connectionId) {
	for (var i in userList) {
		if (userList[i].id == connectionId) {
			return userList[i].user;
		}
	}
	return null;
}
//返回所有的聊天信息
function getAllMessage() {
	let jsonObject = {};
	jsonObject.messages = chatList;
	jsonObject.contentType = 'chatMessages';
	return JSON.stringify(jsonObject);
}

// clinetWebSocket.js

var serverAddress = document.getElementById("serverAdress").value;
var serverPort = document.getElementById("serverPort").value;
var url = "ws://" + serverAddress + ":" + serverPort + "/ChatRoom_modify/chatRoomWebsocket";
var webSocket = new WebSocket(url);
var userName;
//用户注册
function loginUser() {
	userName = document.getElementById("userName").value;
	var user = new User("login", userName);
	//界面模块切换
	document.getElementById("chatPart").style.display = "block";
	document.getElementById("configure").style.display = "none";
	document.getElementById("messages").style.display = "block";
	document.getElementById("connectStatus").style.display = "none";
	document.getElementById("serverAdressTxt").innerHTML = serverAddress;
	document.getElementById("serverPortTxt").innerHTML = serverPort;
	document.getElementById("userNameTxt").innerHTML = userName;
	//发送注册信息
	webSocket.send(JSON.stringify(user));
}
//发送聊天信息
function sendMessage() {
	var chatMessage = document.getElementById("chatMessage");
	var connectionId = document.getElementById("connectionId").value;
	var message = new Message('chat', connectionId, chatMessage.value, getTime());
	chatMessage.value = '';
	webSocket.send(JSON.stringify(message));
}

function User(op, userName) {
	this.op = op;
	this.userName = userName;
}

function Message(op, connectionId, chatMessage, time) {
	this.op = op;
	this.connectionId = connectionId;
	this.chatMessage = chatMessage;
	this.time = time;
}

function getTime() {
	var now = new Date();
	return now.getFullYear() + "/" + (now.getMonth() + 1) + "/" + now.getDate() +
		"" + now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds();
}
webSocket.onerror = function(event) {
	alert(event.data);
};
//与WebSocket建立连接
webSocket.onopen = function(event) {
	document.getElementById('connectDiv').className = "online-img";
};
//处理服务器返回的信息
webSocket.onmessage = function(event) {
	var userList = "";
	var messageList = "";
	var returnContent = eval("(" + event.data + ")");
	console.log(returnContent);
	if (returnContent.contentType == "userSession") {
		document.getElementById('connectionId').value = returnContent.connectionId;
	}
	if (returnContent.contentType == "userOnLineList") {
		var users = returnContent.users;
		for (var i = 0; i < users.length; i++) {
			userList += '<li><span class="' + users[i].user.headImages + '"></span>' + user[i].user.userName +
				'</li>';
		}
		document.getElementById('userOnLine').innerHTML = userList;
		document.getElementById('userList').className = "none-img none";
	}
	if (returnContent.contentType == "newUserOnLine") {
		var userName = returnContent.userName;
		NotificationHandler.showNotification(userName, "上线");
	}
	if (returnContent.contentType == "newUserOffLine") {
		var userName = returnContent.userName;
		NotificationHandler.showNotification(userName, "离线");
	}
	if (returnContent.contentType == "chatMessages") {
		var messages = returnContent.messages;
		var userName = document.getElementById("userNameTxt").innerHTML;
		for (var i = messages.length - 1; i >= 0; i--) {
			if (messages[i].msg.user.userName == userName) {
				messageList += '<li><span class="chatcontent mychatcontent">' +
					messages[i].msg.chatMessage + '</span><span class="' +
					messages[i].msg.user.headImages + '"></span></li>';
			} else {
				messageList += '<li><span class="' +
					messages[i].msg.user.headImages +
					'"></span><span class="chatcontent">' +
					messages[i].msg.chatMessage + '</span></li>';
			}
		}
		document.getElementById('chatList').innerHTML = messageList;
	}
};

<!-- index.html -->

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>基于Node.js实现网络聊天室</title>
		<link rel="stylesheet" type="text/css" href="css/main.css" />
	</head>
	<body>
		<div class="container">
			<!-- header -->
			<div class="header">
				<div id="configure">
					服务器地址:<input type="text" id="serverAdress" value="localhost" />
					服务器端口:<input type="text" id="serverPort" value="8080" />
					昵称:<input type="text" id="userName" />
					<input type="button" class="login-button" onclick="loginUser()" />
				</div>
				<div id="chatPart" class="none">
					服务器地址:<span id="serverAdressTxt"></span>
					服务器端口:<span id="serverPortTxt"></span>
					昵称:<span id="userNameTxt"></span>
				</div>
			</div>
			<div class="banner"></div>
			<!-- content -->
			<div class="content">
				<!-- left -->
				<div class="left">
					<div id="connectStatus">
						<h3 class="gray">用户状态</h3>
						<div id="connectDiv" class="offline-img"></div>
					</div>
					<div id="messages" class="none">
						<h3 class="gray">聊天记录</h3>
						<input type="hidden" id="connectionId" />
						<textarea rows="3" cols="30" id="chatMessage"></textarea>
						<input type="button" class="send-button" onclick="sendMessage()">
						<ul id="chatList">
							<li><span class="head1"></span>
								<span class="chatcontent">欢迎使用聊天室</span>
							</li>
						</ul>
					</div>
				</div>
				<!-- right -->
				<div class="right">
					<h3 class="box">在线用户</h3>
					<div id="userOnLine" class="none-img"></div>
					<ul id="userOnLine"></ul>
				</div>
			</div>
		</div>
		<script type="text/javascript" src="js/notification.js"></script>
		<script type="text/javascript" src="js/clientWebSocket.js"></script>
	</body>
</html>

结果

HTML5——WebSocket:基于Node.js的网络聊天室
HTML5——WebSocket:基于Node.js的网络聊天室

步骤详解

  1. 控制台使用npm init命令对项目初始化
    HTML5——WebSocket:基于Node.js的网络聊天室
  2. 控制台分别使用 npm install express --save-dev 命令、npm install ws --save-dev 命令来安装Express框架、npm install node-uuid --save-dev 命令来安装Express、WebSocket、node_uuid框架
    HTML5——WebSocket:基于Node.js的网络聊天室
    HTML5——WebSocket:基于Node.js的网络聊天室
    HTML5——WebSocket:基于Node.js的网络聊天室
  3. 目录结构
    HTML5——WebSocket:基于Node.js的网络聊天室
  4. 创建服务端脚本index.js ,使用WebSocket框架完成创建服务端
  5. 创建客户端脚本clientWebSocket.js ,完成WebSocket客户端
  6. 实现网络聊天室主界面index.html
  7. 最后在控制台中使用 node index.js 命令启动Node.js服务器,在浏览器中输入 localhost:3000 网址进入测试。

PS

以后可能会用其他工具再次实现这个网络聊天室,到时候做的就会很好用很美观啦~

上一篇:html修改视频速度


下一篇:js复制