构建有多个房间的聊天室程序

1. 程序概览

  • 用户可以在一个简单的表单中输入消息,相互聊天。消息输入后会发送给同一个聊天室内的其他所有用户。

  • 进入聊天室后,程序会自动给用户分配一个昵称,但他们可以用聊天命令修改自己的昵称,如图2-2所示。聊天命令以斜杠(/)开头。

  • 同样,用户也可以输入命令创建新的聊天室(或加入已有的聊天室) ,如图2-3所示。在加入或创建聊天室时,新聊天室的名称会出现在聊天程序顶端的水平条上,也会出现在聊天消息区域右侧的可用房间列表中。

  • 在用户换到新房间后,系统会确认这一变化,如图2-4所示。

2. 程序需要及初始设置

  • 提供静态文件(比如HTML、 CSS和客户端JavaScript);
  • 在服务器上处理与聊天相关的消息;
  • 在用户的浏览器中处理与聊天相关的消息。
  • 第三方的模块mime
  • WebSocket 这是一个为支持实时通讯而设计的轻量的双向通信协议。
  • Socket.IO库 它给不能使用WebSocket的浏览器提供了一些后备措施,包括使用Flash。
  • Express

2.1 提供HTTP和WebSocket服务

2.2 创建程序的文件结构

  • 项目目录:主程序文件会直接放在这个目录下
  • lib子目录:用来放一些服务端逻辑
  • public子目录: 用来放客户端文件
  • 在public子目录下,创建一个javascripts子目录和一个stylesheets目录。

2.2.3 指明依赖项

程序的依赖项是在package.json文件中指明的。这个文件总是被放在程序的根目录下。在package.json文件中可以定义很多事情,但最重要的是程序的名称、版本号、对程序的描述,以及程序的依赖项。

{
  "name": "chatrooms",
  "version": "0.0.1",
  "description": "Minimalist multiroom chat server",
  "dependencies": {
    "socket.io": "~0.9.6",
    "mime": "~1.2.7"
  }
}

2.2.4 安装依赖项

在跟目录输入下面这条命令:

npm install

2.3 提供 HTML、 CSS 和客户端 JavaScript 的服务

2.3.1 创建静态文件服务器

创建静态文件服务器既要用到Node内置的功能,也要用第三方的mime附加模块来确定文件

的的MIME类型。

  1. 发送文件数据及错误响应

接下来要添加三个辅助函数以提供静态HTTP文件服务。第一个是在所请求的文件不存在时

发送404错误的。把下面的辅助函数加到server.js中:

function send404(response) {
    response.writeHead( 404, { ‘Content-Type‘: ‘text/plain‘ } ) ;
    response.write( ‘Error 404: resource not found.‘ ) ;
    response.end() ;
}

第二个辅助函数提供文件数据服务。这个函数先写出正确的HTTP头,然后发送文件的内容。

把下面的代码添加到server.js中:

function sendFile(response, filePath, fileContents) {
    response.writeHead(
        200,
        { ‘Content-type‘: mime.lookup( path.basename( filePath ) ) }
    ) ;
    response.end( fileContents ) ;
}

访问内存(RAM)要比访问文件系统快得多,所以Node程序通常会把常用的数据缓存到内

存里。我们的聊天程序就要把静态文件缓存到内存中,只有第一次访问的时候才会从文件系统中

读取。下一个辅助函数会确定文件是否缓存了,如果是,就返回它。如果文件还没被缓存,它会

从硬盘中读取并返回它。如果文件不存在,则返回一个HTTP 404错误作为响应。把这个辅助函

数加到server.js中:

  1. 创建HTTP服务器

  1. 启动HTTP服务器
server.listen( 3000, function () {
    console.log( ‘Server listening on port 3000.‘ ) ;
} ) ;

启动服务器:

node server.js

2.3.2 添加HTML和CSS文件

2.4 用 Socket.IO 处理与聊天相关的消息

处理浏览器和服务器之间的通信。现代浏览器能用WebSocket处理浏览器跟服务器两者之间的通

信(参见Socket.IO浏览器支持页以了解详情: http://socket.io/#browser-support)。

  • 简要介绍下Socket.IO,并确定要在服务器端使用的Socket.IO功能;
  • 添加代码设置Socket.IO服务器;
  • 添加代码处理各种聊天程序的事件。

Socket.IO提供了开箱即用的虚拟通道,所以程序不用把每条消息都向已连接的用户广播,而

是只向那些预订了某个通道的用户广播。

Socket.IO还是事件发射器(Event Emitter)的好例子。事件发射器本质上是组织异步逻辑的

一种很方便的设计模式。

事件发射器:事件发射器是跟某种资源相关联的,它能向这个资源发送消息,也能从这个资源接收消息。

资源可以连接远程服务器,或者更抽象的东西,比如游戏中的角色。 Johnny-Five项目

https://github.com/rwldrn/johnny-five)是一个用Node做的机器人程序,实际上就是用事件发射

器控制Arduino微控制器。

2.4.1 设置Socket.IO服务器

server.js

var chatServer = require( ‘./lib/chat_server‘ ) ;
chatServer.listen( server ) ;

现在你要在lib目录中创建一个新文件, chat_server.js。先把下面的变量声明添加到这个文件

中。这些声明让我们可以使用Socket.IO,并初始化了一些定义聊天状态的变量:

var socketio = require( ‘socket.io‘ ) ;
var io ;
var guestNumber = 1 ;
var nickNames = {} ;
var namesUsed = [] ;
var currentRoom = {} ;
  • 确立建立连接

接下来添加代码清单2-7中的逻辑,定义聊天服务器函数listen。server.js中会调用这个函数。

它启动Socket.IO服务器,限定Socket.IO向控制台输出的日志的详细程度,并确定该如何处理每个

接进来的连接。

2.4.2 处理程序场景及事件

  • 分配昵称
  • 房间更换请求
  • 昵称更换请求
  • 发送聊天服务
  • 房间创建
  • 用户断开连接
  • 分配昵称

要添加的第一个辅助函数是assignGuestName,用来处理新用户的昵称。当用户第一次连到聊天服务器上时,用户会被放到一个叫做Lobby的聊天室中,并调用assignGuestName给他们分配一个昵称,以便可以相互区分开。

程序分配的所有昵称基本上都是在Guest后面加上一个数字,有新用户连进来时这个数字就会往上增长。用户昵称存在变量nickNames中以便于引用,并且会跟一个内部socket ID关联。昵称还会被添加到namesUsed中,这个变量中保存的是已经被占用的昵称。把下面清单中的代码添加到lib/chat_server.js中实现这个功能。

  • 进入聊天室

  • 处理昵称变更请求

  • 发送聊天消息
function handleMessageBroadcasting(socket) {
    socket.on( ‘message‘, function (message) {
        socket.broadcast.to( message.room ).emit( ‘message‘, {
            text: nickNames[ socket.id ] + ‘: ‘ + message.text
        } ) ;
    } ) ;
}
  • 创建房间
function handleRoomJoining(socket) {
    socket.on( ‘join‘, function (room) {
        socket.leave( currentRoom[ socket.id ] )
        joinRoom( socket, room.newRoom ) ;
    } ) ;
}
  • 用户断开连接
function handleClientDisconnection(socket) {
    socket.on( ‘disconnect‘, function () {
        var nameIndex = namesUsed.indexOf( nickNames[ socket.id ] ) ;
        delete namesUsed[ nameIndex ] ;
        delete nickNames[ socket.id ] ;
    } ) ;
}

2.5 在程序的用户界面上使用客户端 JavaScript

  • 向服务器发送用户的消息和昵称/房间变更请求
  • 显示其他用户的消息,以及可用房间的列表

2.5.2 将消息和昵称/房间变更请求传给服务器

要添加的第一段客户端JavaScript代码是一个JavaScript原型对象,用来处理聊天命令、发送

消息、请求变更房间或昵称。

在public/javascripts目录下创建一个chat.js文件,把下面的代码放进去。

/**
 * Created by 23782 on 2016/4/19.
 */
var Chat = function (socket) {
    this.socket = socket ;
}

// 发送消息
Chat.prototype.sendMessage = function (room, text) {
    var message = {
        room: room,
        text: text
    } ;
    this.socket.emit( ‘message‘, message ) ;
}

// 变更房间
Chat.prototype.changeRoom = function (room) {
    this.socket.emit( ‘join‘, {
        newRoom: room
    } ) ;
}

// 处理聊天命令
Chat.prototype.processCommand = function (command) {
    var words = command.split( ‘ ‘ ) ;
    var command = words[ 0 ].substring( 1, words[ 0 ].length ).toLowerCase() ;
    var message = false ;

    switch ( command ) {
        case ‘join‘: {
            words.shift() ;
            var room = words.join( ‘ ‘ ) ;
            this.changeRoom( room ) ;
            break ;
        } ;
        case ‘nick‘: {
            words.shift() ;
            var name = words.join( ‘ ‘ ) ;
            this.socket.emit( ‘nameAttempt‘, name ) ;
            break ;
        }
        default: {
            message = ‘Unrecognized command‘ ;
            break ;
        }
    }

    return message ;
}

2.5.2 在用户界面中显示消息及可用房间

现在该添加使用jQuery跟用户界面(基于浏览器)直接交互的逻辑了。要添加的第一个功能

是显示文本数据。;

从安全角度来看, Web程序中有两种文本数据。一种是受信的文本数据,由程序提供的文本组成,另一种是可疑的文本数据,是由程序的用户创建的文本,或从用户创建的文本中提取出来的。我们之所以认为来自用户的文本数据是可疑的,是因为恶意用户可能会蓄意在提交的文本数据中包含\

function divEscapedContentElement(message) {
    return $( ‘<div></div>‘ ).text( message ) ;
}

function divSystemContentElement(message) {
    return $( ‘<div></div>‘ ).html( ‘<i>‘ + message + ‘</i>‘ ) ;
}

下一个要加到chat_ui.js中的函数是用来处理用户输入的,具体内容见代码清单2-12。如果用

户输入的内容以斜杠(/)开头,它会将其作为聊天命令处理。如果不是,就作为聊天消息发送

给服务器并广播给其他用户,并添加到用户所在聊天室的聊天文本中。

// 处理原始的用户输入
function processUserInput(chatApp, socket) {
    var message = $( ‘#send-message‘ ).val() ;
    var systemMessage ;

    if ( message.charAt( 0 ) == ‘/‘ ) {
        systemMessage = chatApp.processCommand( message ) ;
        if ( systemMessage ) {
            $( ‘#messages‘ ).append( divSystemContentElement( systemMessage ) ) ;
        }
    } else {
        chatApp.sendMessage( $( ‘#room‘ ).text(), message ) ;
        $( ‘#messages‘ ).append( divEscapedContentElement( message ) ) ;
        $( ‘#messages‘ ).scrollTop( $( ‘#messages‘ ).prop( ‘scrollHeight‘ ) ) ;
    }

    $( ‘#send-message‘ ).val( ‘‘ ) ;
}

辅助函数现在已经定义好了,你还需要添加下面这个代码清单中的逻辑,它要在用户的浏览器加载完页面后执行。这段代码会对客户端的Socket.IO事件处理进行初始化。

var socket = io.connect() ;

$( document ).ready( function () {
    var chatApp = new Chat( socket ) ;

    socket.on( ‘nameResult‘, function (result) {
        var message ;

        if ( result.success ) {
            message = ‘You are now known as ‘ + result.name + ‘. ‘ ;
        } else {
            messge = result.messge ;
        }
        $( ‘#messages‘ ).append( divSystemContentElement( message ) ) ;
    } ) ;

    socket.on( ‘joinResult‘, function (result) {
        $( ‘#room‘ ).text( result.room ) ;
        $( ‘#messages‘ ).append( divSystemContentElement( ‘Room changed.‘ ) ) ;
    } ) ;

    socket.on( ‘message‘, function (message) {
        var newElement = $( ‘<div></div>‘ ).text( message.text ) ;
        $( ‘#messages‘ ).append( newElement ) ;
    } ) ;

    socket.on( ‘rooms‘, function (rooms) {
        $( ‘#room-list‘ ).empty() ;

        for( var room in rooms ) {
            room = room.substring( 1, room.length ) ;
            if ( room != ‘‘ ) {
                $( ‘#room-list‘ ).append( divEscapedContentElement( room ) ) ;
            }
        }

        $( ‘#room-list div‘ ).click( function () {
            chatApp.processCommand( ‘/join‘ + $( this ).text() ) ;
            $( ‘#send-message‘ ).focus() ;
        } ) ;
    } ) ;

    setInterval( function () {
        socket.emit( ‘rooms‘ ) ;
    }, 1000 ) ;

    $( ‘#send-message‘ ).focus() ;

    $( ‘#send-form‘ ).submit( function () {
        processUserInput( chatApp, socket ) ;
        return false ;
    } ) ;

} ) ;

接下来让我们把程序做完,将下面代码清单中的CSS样式代码添加到public/stylesheets/style.css文件中。

#room-list {
    float: right;
    width: 100px;
    height: 300px;
    overflow: auto;
}

#room-list div {
    border-bottom: 1px solid #eeeeee;
}

#room-list div:focus {
    background-color: #dddddd;
}

#send-message {
    width: 700px;
    margin-bottom: 1em;
    margin-right: 1em;
}

#help {
    font: 10px "Lucida Grande", Helvetica, Arial, sans-serif;
}

加好最后的代码,让我们把程序跑起来试试(用node server.js) 。

  • 个人效果图:

时间: 2024-08-06 22:39:11

构建有多个房间的聊天室程序的相关文章

Erlang 聊天室程序

Erlang 聊天室程序( 一) Erlang 聊天室程序(二) 客户端的退出 Erlang 聊天室程序(三) 数据交换格式---json的decode Erlang 聊天室程序(四) 数据交换格式---json的encode Erlang 聊天室程序(五) 设置客户端信息 Erlang 聊天室程序(七) 获取在线用户 Erlang 聊天室程序(八) 主题房间---supervisor 的使用 Erlang 聊天室程序(九) 主题房间2 ---房间信息管理 Erlang 聊天室程序(十) 主题房

ASP.NET 使用application和session对象写的简单聊天室程序

ASP.Net中有两个重要的对象,一个是application对象,一个是session对象. Application:记录应用程序参数的对象,该对象用于共享应用程序级信息. Session:记录浏览器端的变量对象,用来存储跨网页程序程序的变量或者对象. 说实话,写了快一年的asp.net,application对象还真没怎么用过.看了看书,根据这两个对象的特性写了一个简单的聊天室程序.真的是非常的简陋. 我的思路是,有两个页面Default页和ChatRoom页,页面布局如图: Default

I/O复用——聊天室程序

本文主要是为熟悉Linux下网络编程,而实现一个简单的网络聊天室程序.  以Poll实现I/O复用技术来同时处理网络连接和用户输入,实现多个用户同时在线群聊. 其中客户端实现两个功能:一:从标准输入读入用户数据,并将用户数据发送到服务器:二:接收服务器发送的数据,并在标准输出打印. 服务端功能为:接收客户端数据,并将客户数据发送到登录到该服务端的所有客户端(除数据发送的客户端外). 服务端程序 chat_server: #define _GNU_SOURCE 1 #include<sys/typ

java socket控制台版本聊天室程序源码下载

原文:java socket控制台版本聊天室程序源码下载 代码下载地址:http://www.zuidaima.com/share/1550463257578496.htm java socket控制台版本聊天室程序源码下载,学习的时候写的,适合学习java基础 java网络编程基础用 标签: java socket 控制台 聊天室 源码话题: 网络编程 java socket控制台版本聊天室程序源码下载,布布扣,bubuko.com

15.基于UDP协议的聊天室程序

使用UDP协议完成一个聊天室程序的小项目,大部分代码都有注释,一看就能看到的. 实现的功能:               (1)查看/显示已经登陆的用户信息               (2)向已登陆的用户发送消息               (3)输出错误消息,给予提示               (4)退出 共有三个文件: chat_public.h #ifndef _CHAT_PUB_H_ #define _CHAT_PUB_H_ //chat_public.h #include <lis

Java网络编程 - 基于UDP协议 实现简单的聊天室程序

最近比较闲,一直在抽空回顾一些Java方面的技术应用. 今天没什么事做,基于UDP协议,写了一个非常简单的聊天室程序. 现在的工作,很少用到socket,也算是对Java网络编程方面的一个简单回忆. 先看一下效果: 实现的效果可以说是非常非常简单,但还是可以简单的看到一个实现原理. "聊天室001"的用户,小红和小绿相互聊了两句,"聊天室002"的小黑无人理会,在一旁寂寞着. 看一下代码实现: 1.首先是消息服务器的实现,功能很简单: 将客户端的信息(进入了哪一个聊

nodejs构建多房间简易聊天室

1.前端界面代码 前端不是重点,够用就行,下面是前端界面,具体代码可到github下载. 2.服务器端搭建 本服务器需要提供两个功能:http服务和websocket服务,由于node的事件驱动机制,可将两种服务搭建在同一个端口下. 1.包描述文件:package.json,这里用到了两个依赖项,mime:确定静态文件mime类型,socket.io:搭建websocket服务,然后使用npm install  安装依赖 { "name": "chat_room",

nodejs多房间web聊天室

一年之前的做的小项目,过了许久,翻出当时的PPT文档总结一下.源码下载:https://github.com/CreekLou/chatRoom Nodejs背景简介 1 ,JavaScript最早是运行在浏览器中,然而浏览器只是提供了一个上下文 2 ,node.js事实上就是另外一种上下文,它允许在后端(脱离浏览器环境)运行JavaScript代码 3 ,Node.js事实上既是一个运行时环境,同时又是一个库 Nodejs架构如下图 Node.js 的异步机制是基于事件的,所有的磁盘 I/O

&#8203;下面为大家介绍一个运用自己电脑当成服务器,然后开发一个简单的php聊天室程序的方法:

上一期我们说过B/S技术开发聊天有什么优点,这一期我们就来简单的说说用C/S技术开发又有什么特点? 一.稳定性和灵活性:用C/S技术可以将应用和服务进行分离.二.安全性:C/S对应是的是结构模式,一般只适用于局域网,所以安全性比较好.三.速度快:客户端与服务器端是直接连接的,中间没有经过别的环节,所以响应速度非常快.四.升级维护复杂:如果软件需要升级维护,那么每一台客户的机子都要进行相应的升级维护服务,那么这个过程肯定是比较繁琐的.综上所述,对于不同的聊天室需要采用不同的开发技术,但是国内目前很