【转载】Node.js + WebSocket 实现的简易聊天室
Node.js + WebSocket 实现的简易聊天室
本实例程序在Windows下测试通过。
上述实例支持以下浏览器:
Firefox 7-9 (Old) (Protocol Version 8)
Firefox 10+ (Protocol Version 13)
Chrome 14,15 (Old) (Protocol Version 8)
Chrome 16+ (Protocol Version 13)
Internet Explorer 10 (Preview) (Protocol Version 13)
消息的传递也比较简单,Client –> Server, Server –> Client

服务器广播消息

数据传输使用的是JSON格式,前台建立连接的代码比较简单,ex:
1: $(function () {
2: window.WebSocket = window.WebSocket || window.MozWebSocket; 3: 4: var connection = new WebSocket('ws://127.0.0.1:1337');
5: 6: connection.onopen = function () {
7: //已建立连接
8: }; 9: 10: connection.onerror = function (error) {
11: //接收或发送消息时遇到了错误
12: }; 13: 14: connection.onmessage = function (message) {
15: 16: try {
17: var json = JSON.parse(message.data);
18: } catch (e) {
19: console.log('不能被正常解析的数据:', message.data);
20: return;
21: } 22: 23: // todo
24: }; 25: });后端的实现,直接使用别人写好的模块所以传统比较简单一点(想在Windows下运行chat-server还是有点麻烦的),因为该模块在Windows下安装时,需要Microsoft Visual C++和Python 2.7的支持。--如果没有安装这两个东东,还得先安装一下。
如果顺利的话,会看到如下图所示的界面:

这样我们就可以创建Server了,实现的代码也并不复杂:
1: var WebSocketServer = require('websocket').server;
2: var http = require('http');
3: 4: var server = http.createServer(function(request, response) {
5: console.log((new Date()) + ' Received request for ' + request.url);
6: response.writeHead(404); 7: response.end(); 8: });9: server.listen(8080, function() {
10: console.log((new Date()) + ' Server is listening on port 8080');
11: }); 12: 13: wsServer = new WebSocketServer({
14: httpServer: server,15: // You should not use autoAcceptConnections for production
16: // applications, as it defeats all standard cross-origin protection
17: // facilities built into the protocol and the browser. You should
18: // *always* verify the connection's origin and decide whether or not
19: // to accept it.
20: autoAcceptConnections: false
21: }); 22: 23: function originIsAllowed(origin) {
24: // put logic here to detect whether the specified origin is allowed.
25: return true;
26: } 27: 28: wsServer.on('request', function(request) {
29: if (!originIsAllowed(request.origin)) {
30: // Make sure we only accept requests from an allowed origin
31: request.reject();32: console.log((new Date()) + ' Connection from origin ' + request.origin + ' rejected.');
33: return;
34: } 35: 36: var connection = request.accept('echo-protocol', request.origin);
37: console.log((new Date()) + ' Connection accepted.');
38: connection.on('message', function(message) {
39: if (message.type === 'utf8') {
40: console.log('Received Message: ' + message.utf8Data);
41: connection.sendUTF(message.utf8Data); 42: }43: else if (message.type === 'binary') {
44: console.log('Received Binary Message of ' + message.binaryData.length + ' bytes');
45: connection.sendBytes(message.binaryData); 46: } 47: });48: connection.on('close', function(reasonCode, description) {
49: console.log((new Date()) + ' Peer ' + connection.remoteAddress + ' disconnected.');
50: }); 51: });从上述的例子中可以看出,websocket支持两种传递方式:二进制流、utf8的文本流。前面的例子中所使用的是utf8文本流
完整的chat-server.js的代码如下:
1: // http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/
2: "use strict";
3: 4: // Optional. You will see this name in eg. 'ps' or 'top' command
5: process.title = 'node-chat';
6: 7: //websocket服务器监听的端口
8: var webSocketsServerPort = 1337;
9: 10: var webSocketServer = require('websocket').server;
11: var http = require('http');
12: 13: //保存最近100条消息记录
14: var history = [ ];
15: 16: //当前连接的客户端
17: var clients = [ ];
18: 19: /**
20: * 对聊天内容进行字符转义
21: */
22: function htmlEntities(str) {
23: return String(str).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
24: } 25: 26: 27: var colors = [ 'red', 'green', 'blue', 'magenta', 'purple', 'plum', 'orange' ]; 28: colors.sort(function(a,b) { return Math.random() > 0.5; } ); 29: 30: /** 31: * HTTP server 32: */ 33: var server = http.createServer(function(request, response) {}); 34: 35: server.listen(webSocketsServerPort, function() {36: console.log(getNow() + " WebSocket Server is listening on port:" + webSocketsServerPort);
37: }); 38: 39: /** 40: * WebSocket server 41: * WebSocket server is tied to a HTTP server. To be honest I don't understand why. 42: */ 43: var wsServer = new webSocketServer({ 44: httpServer: server 45: }); 46: 47: //每一个客户端请求建立连接时,都将触发此方法 48: wsServer.on('request', function(request) { 49: 50: console.log(getNow() + ' ' + request.origin + ' 请求连接.'); 51: 52: // accept connection - you should check 'request.origin' to make sure that client is connecting from your website 53: // (http://en.wikipedia.org/wiki/Same_origin_policy) 54: var connection = request.accept(null, request.origin); 55: 56: //保存当前请求连接客户端的索引,以方便在断开连接时,从连接池中移除该连接 57: var index = clients.push(connection) - 1; 58: var userName; 59: var userColor; 60: 61: console.log(getNow() + ' 已建立连接...'); 62: 63: //推送历史聊天记录 64: if (history.length > 0) { 65: connection.sendUTF(JSON.stringify({type: 'history', data: history})); 66: } 67: 68: //某一客户端发送消息过来 69: connection.on('message', function(message) { 70: if (message.type === 'utf8') { 71: 72: //第一次请求用于保存用户信息 73: if (!userName) { 74: userName = htmlEntities(message.utf8Data); 75: 76: userColor = colors.shift(); 77: connection.sendUTF(JSON.stringify({ type:'color', data: userColor })); 78: console.log(getNow() + ' 用户已登录: ' + userName + ' -- ' + userColor); 79: 80: } else { 81: //记录消息并广播 82: console.log(getNow() + userName + '-说: ' + message.utf8Data); 83: 84: //传递给客户端的数据格式 85: var obj = { 86: time: (new Date()).getTime(), 87: text: htmlEntities(message.utf8Data), 88: author: userName, 89: color: userColor 90: }; 91: history.push(obj); 92: 93: //取数组最后100条消息记录并保存 94: history = history.slice(-100); 95: 96: //将消息广播给所有客户端 97: var json = JSON.stringify({ type:'message', data: obj }); 98: for (var i=0; i < clients.length; i++) { 99: clients[i].sendUTF(json); 100: } 101: 102: console.log("总的客户端连接数:" + clients.length);
103: } 104: } 105: }); 106: 107: //用户断开连接 108: connection.on('close', function(connection) { 109: if (!userName && !userColor) {110: console.log(getNow() + " -- " + connection.remoteAddress + " 断开链接.");
111: 112: //从连接池中移除连接 113: clients.splice(index, 1); 114: 115: //回收访用户所使用的颜色 116: colors.push(userColor); 117: } 118: }); 119: 120: }); 121: 122: function getNow() { 123: return new Date().format('yyyy-MM-dd hh:mm:ss'); 124: } 125: 126: Date.prototype.format = function (fmt) { //author: meizz 127: var o = {128: "M+": this.getMonth() + 1,
129: "d+": this.getDate(),
130: "h+": this.getHours(),
131: "m+": this.getMinutes(),
132: "s+": this.getSeconds(),
133: "q+": Math.floor((this.getMonth() + 3) / 3),
134: "S": this.getMilliseconds()
135: };136: if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
137: for (var k in o)138: if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
139: return fmt;
140: }运行supervisor chat-server.js或者node chat-server.js 就OK了~


使用Firefox测试一下:)

本文参考:
分类: Node.js
虽功未成,亦未敢藏私,众侠诸神通尽录于此,竟成一笈,名葵花宝典,以飨后世。
邮箱:steven9801@163.com
QQ: 48039387
邮箱:steven9801@163.com
QQ: 48039387
浙公网安备 33010602011771号