• 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, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
      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测试一下:)

    image

    本文参考:

    1、Node.js & WebSocket - Simple chat tutorial

    2、WebSocket-Node

  • 相关阅读:
    Java输出文件到本地(输出流)
    Java 工厂设计模式
    实际工作与JAVA面试题
    JAVA 转义字符串中的特殊字符
    Oracle工作笔记
    JS验证表单中TEXT文本框中是否含有非法字符
    JAVA 解析TXT文本
    表单异步提交数据
    rem.js(2)
    rem.js(1)
  • 原文地址:https://www.cnblogs.com/meteoric_cry/p/2608959.html
Copyright © 2020-2023  润新知