如何使用Socket.IO编写聊天应用程序

本文介绍如何使用Socket.IO和Backbone.js构建实时聊天应用。通过客户端和服务器端代码示例,展示了如何实现用户登录、聊天消息发送及用户状态更新等功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

[原文地址:http://www.gbtags.com/gb/share/3102.htm]


这篇文章要介绍如何使用Socket.IOBackbone.js构建一个简单的聊天应用程序。Socket.IO主要用于开发具有高度交互性、实时性的web应用程序,比如聊天系统或者多人游戏。 Backbone.js可以帮助开发者在Web应用程序中向Javascript代码添加架构的组件库,让开发者很容易地管理应用和分离耦合的处理逻辑。阅读这篇文章之前,大家至少应该熟悉Node.js和Express。如果熟悉Backbone.js和Underscore.js就更好了,这些技术都将运用于基本的模板建立。


介绍

如下图所示,解释了客户端代码的结构。中间是一个控制器,它充当了socket客户端与视图之间的桥梁。控制器从sock客户端获取更新,然后告诉Model。model再将更新传回给Backbone绑定的视图。


客户端

我们将首先通过查看客户端代码。所有聊天互动都有HomeView处理,首先需要在 /public/js/models/main.js中定义HomeModel。

var HomeModel = Backbone.Model.extend({
  defaults: {
    // Backbone collection for users
    onlineUsers: new UserCollection(),
 
    // Backbone collection for user chats, 初始化一个预定义聊天模型
    userChats: new ChatCollection([
      new ChatModel({sender: '', message: 'Chat Server v.1'})
    ])
  },
 
  // 添加一个新用户到 onlineUsers collection
  addUser: function(username) {
    this.get('onlineUsers').add(new UserModel({name: username}));
  },
 
  // 从onlineUsers collection中移除一个用户
  removeUser: function(username) {
    var onlineUsers = this.get('onlineUsers');
    var u = onlineUsers.find(function(item) {
          return item.get('name') == username;
        });
 
    if (u) {
      onlineUsers.remove(u);
    }
  },
 
  // 添加一个新的聊天到 userChats collection
  addChat: function(chat) {
    this.get('userChats').add(new ChatModel({sender: chat.sender, message: chat.message}));
  },
});

我们利用Backbone集合来侦听集合变化。这些集合的更新会直接由视图自动反映出来。接下来,需要在/public/index.html中定义home模板。

<script type="text/template" id="home-template">
  <div class="row">
    <div class="col-md-10">
      <div class="panel panel-default">
        <div class="panel-heading">Lobby</div>
        <div class="panel-body">
          <div class="nano">
            <div class="content">
              <div class="list-group" id="chatList"></div>
            </div>
          </div>
          <form>
            <input class="form-control" type="text" id="chatInput"></input>
          </form>
        </div>
      </div>
    </div>
    <div class="col-md-2">
      <div class="panel panel-default">
        <div class="panel-heading">
          <h3 class="panel-title">Online Users <span class="badge pull-right" id="userCount"></span></h3>
        </div>
        <div class="panel-body">
          <div class="nano">
            <div class="content">
              <div class="list-group" id="userList"></div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</script>

聊天客户端

接下来,让我们来定义我们的Socket.IO聊天客户端客户端与服务器端的通信,主要通过发送消息和监听通知来完成这些通知触发事件与所述控制器进行通信。请参阅下面/public/ JS/ socketclient.js的代码

var ChatClient = function(options) {
  // 避免冲突
  var self = this;
 
  // app event bus
  self.vent = options.vent;
 
  // server hostname replace with your server's hostname eg: http://localhost
  self.hostname = 'http://chatfree.herokuapp.com';
 
  // connects to the server
  self.connect = function() {
    // connect to the host
    self.socket = io.connect(self.hostname);
 
    // set responseListeners on the socket
    self.setResponseListeners(self.socket);
  }
 
  // send login message
  self.login = function(name) {
    self.socket.emit('login', name);
  }
 
  // send chat message
  self.chat = function(chat) {
    self.socket.emit('chat', chat);
  }
 
  self.setResponseListeners = function(socket) {
    // handle messages from the server
    socket.on('welcome', function(data) {
      // request server info
      socket.emit('onlineUsers');
 
      self.vent.trigger('loginDone', data);
    });
 
    socket.on('loginNameExists', function(data) {
      self.vent.trigger('loginNameExists', data);
    });
 
    socket.on('loginNameBad', function(data) {
      self.vent.trigger('loginNameBad', data);
    });
 
    socket.on('onlineUsers', function(data) {
      console.log(data);
      self.vent.trigger('usersInfo', data);
    });
 
    socket.on('userJoined', function(data) {
      self.vent.trigger('userJoined', data);
    });
 
    socket.on('userLeft', function(data) {
      self.vent.trigger('userLeft', data);
    });
 
    socket.on('chat', function(data) {
      self.vent.trigger('chatReceived', data);
    });
  }
}

使用Socket.IO可以非常简单的发送和接受通信数据,上面的代码中,使用了下面的两个方法

socket.emit(message, [callback])  向服务器端发送消息

socket.on(message, callback)      用于接收来自服务器的消息

让我们来看一下他们的通信协议

主控制器

客户端最后一步,主控制器,它控制了VIEW,MODEL和socket客户端,代码在/public/js/main.js中

var MainController = function() {
  var self = this;
 
  // Event Bus for socket client
  self.appEventBus = _.extend({}, Backbone.Events);
  // Event Bus for Backbone Views
  self.viewEventBus = _.extend({}, Backbone.Events);
 
  // initialize function
  self.init = function() {
    // create a chat client and connect
    self.chatClient = new ChatClient({vent: self.appEventBus});
    self.chatClient.connect();
 
    // create our views, place login view inside container first.
    self.loginModel = new LoginModel();
    self.containerModel = new ContainerModel({
      viewState: new LoginView({
        vent: self.viewEventBus,
        model: self.loginModel
      })
    });
    self.containerView = new ContainerView({model: self.containerModel});
    self.containerView.render();
  };
 
  // View Event Bus Message Handlers
  self.viewEventBus.on('login', function(name) {
    // socketio login
    self.chatClient.login(name);
  });
 
  self.viewEventBus.on('chat', function(chat) {
    // socketio chat
    self.chatClient.chat(chat);
  });
 
  // Socket Client Event Bus Message Handlers
 
  // triggered when login success
  self.appEventBus.on('loginDone', function() {
    self.homeModel = new HomeModel();
    self.homeView  = new HomeView({vent: self.viewEventBus, model: self.homeModel});
 
    // set viewstate to homeview
    self.containerModel.set('viewState', self.homeView);
  });
 
  // triggered when login error due to bad name
  self.appEventBus.on('loginNameBad', function(name) {
    self.loginModel.set('error', 'Invalid Name');
  });
 
  // triggered when login error due to already existing name
  self.appEventBus.on('loginNameExists', function(name) {
    self.loginModel.set('error', 'Name already exists');
  });
 
  // triggered when client requests users info
  // responds with an array of online users.
  self.appEventBus.on('usersInfo', function(data) {
    var onlineUsers = self.homeModel.get('onlineUsers');
    var users = _.map(data, function(item) {
      return new UserModel({name: item});
    });
 
    onlineUsers.reset(users);
  });
 
  // triggered when a client joins the server
  self.appEventBus.on('userJoined', function(username) {
    self.homeModel.addUser(username);
    self.homeModel.addChat({sender: '', message: username + ' joined room.'});
  });
 
  // triggered when a client leaves the server
  self.appEventBus.on('userLeft', function(username) {
    self.homeModel.removeUser(username);
    self.homeModel.addChat({sender: '', message: username + ' left room.'});
  });
 
  // triggered when chat receieved
  self.appEventBus.on('chatReceived', function(chat) {
    self.homeModel.addChat(chat);
  });
}
最后,我们需要定义一个MainController入口,调用init方法,代码位于/public/js/main.js中

$(document).ready(function() {
  var mainController = new MainController();
 
  mainController.init();
});

这就是一个完整的客户端代码了,我们可以通过CHROME的DEBUG工具,看到信息交换的内容。

服务器端

下面我们来看服务器端,是如何用Node.js, Express, 和Socket.IO来实现的。代码位于/scripts/web.js中

// requirements
var express = require('express');
var http = require('http');
var socketio = require('socket.io');
var path = require('path');
 
// routes
var routes = require('../routes/index.js');
 
var app = express();
 
// routes middleware
app.use(app.router);
// serve public folder
app.use(express.static(path.join(__dirname, '../public')));
 
// serve index.html for every path
app.use(routes.index);
 
// this is how you use socket io with express
var server = http.createServer(app);
var io = socketio.listen(server);
 
var port = process.env.PORT || 8080;
 
server.listen(port, function() {
  console.log(' - listening on ' + port+ ' ' + __dirname);
});
 
// require our chatserver
var ChatServer = require('./chatserver');
 
// initialize a new chat server.
new ChatServer({io: io}).init();

聊天服务器端

应用程序的最后一部分是聊天服务器。它主要负责维护在线用户列表,广播聊天消息。比如,首先,服务器会给一个新的客户的连接请求命名,然后通过刚刚建立的socket,连接事件handlers。socket handler处理如下事件:    socket.on(message, callback)  - 在收到新邮件时回调函数被调用。消息可以是任何类型的数据,这取决于发送的消息。    socket.on('disconnect', callback) - 当socket断开连接时候,回调函数被调用。    socket.emit(message, args) - 通过socket发送消息。     socket.broadcast.send(message, args)  - 广播信息到除发送者之外的所有socket。现在,我们已经看到了handler socket是如何工作的。首先,需要在/scripts/chatserver.js中定义一个用户模型 :

// User Model
var User = function(args) {
  var self = this;
 
  // Socket field
  self.socket = args.socket;
  // username field
  self.user = args.user;
}

 然后,看一下具体的代码

var Server = function(options) {
  var self = this;
 
  self.io = options.io;
 
  // users array
  self.users = [];
 
  // initialize function
  self.init = function() {
    // Fired upon a connection
    self.io.on('connection', function(socket) {
      self.handleConnection(socket);
    });
  }
 
  // socket handler for an incoming socket
  self.handleConnection = function(socket) {
    // wait for a login message
    socket.on('login', function(username) {
      var nameBad = !username || username.length < 3 || username.length > 10;
 
      // check for badname
      if (nameBad) {
        socket.emit('loginNameBad', username);
        return;
      }
 
      var nameExists = _.some(self.users, function(item) {
        return item.user == username;
      });
 
      // check for already existing name
      if (nameExists) {
        socket.emit('loginNameExists', username);
      } else {
        // create a new user model
        var newUser = new User({ user: username, socket: socket });
        // push to users array
        self.users.push(newUser);
        // set response listeners for the new user
        self.setResponseListeners(newUser);
        // send welcome message to user
        socket.emit('welcome');
        // send user joined message to all users
        self.io.sockets.emit('userJoined', newUser.user);
      }
    });
  }
 
  // method to set response listeners
  self.setResponseListeners = function(user) {
    // triggered when a socket disconnects
    user.socket.on('disconnect', function() {
      // remove the user and send user left message to all sockets
      self.users.splice(self.users.indexOf(user), 1);
      self.io.sockets.emit('userLeft', user.user);
    });
    // triggered when socket requests online users
    user.socket.on('onlineUsers', function() {
      var users = _.map(self.users, function(item) {
        return item.user;
      });
 
      user.socket.emit('onlineUsers', users);
    });
 
    // triggered when socket send a chat message
    user.socket.on('chat', function(chat) {
      if (chat) {
        self.io.sockets.emit('chat', { sender: user.user, message: chat });
      }
    });
  }
}

总结

我们已经看到了如何使用Backbone和Socket.IO构建一个简单的聊天应用程序。还有很多没有在本文中涉及的Socket.IO性能,例如rooms和namespaces。通过这篇文章,我们可以看出使用Socket.IO很容易的在客户端和服务器端交换消息。具体代码可以直接下载。这里查看

在线演示

参考:http://www.sitepoint.com/chat-application-using-socket-io/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值