0

这肯定已经被问了一千次了,但我没有找到任何令人满意的答案,所以我会尝试再试一次,尽可能清楚。

我从一个干净的 Express 开始;通常通过以下终端命令完成的一个:

user$ express
user$ npm install

然后我继续安装socket.io,这样:

user$ npm install socket.io --save

在我的 main.js 文件中,我有以下内容:

//app.js
var express  = require('express'),
  http     = require('http'),
  path     = require('path'),
  io       = require('socket.io'),
  routes   = require('./routes');

var app = express();

我通过将它附加到我的快递服务器来启动我的 socket.io 服务器:

//app.js
var server = http.createServer(app).listen(app.get('port'), function(){
  console.log('express server started!');
});

var sIo = io.listen(server);

我现在要做的是设置 Express 使用的常用路线:

//app.js
app.get('/', routes.index);
app.get('/send/:recipient/:text', routes.sendMessage);

现在,由于我喜欢让事情井井有条,我想将我的 socket.io 代码放在另一个文件中,而不是使用通常的代码:

//app.js
sIo.sockets.on('connection', function(socket){
  console.log('got a connection');
});

我使用以下内容来访问套接字sIo 对象(因为该对象包含所有连接信息(重要)):

//app.js
sIo.sockets.on('connection', function(socket){
  routes.connection(sIo, socket);
});

// index.js (./routes)
exports.connection = function(sIo, socket){
  console.log('got a connection.');
};

这样我就可以在这里完成我所有的 socket.io 工作。我知道我现在可以从 sIo 对象访问我所有的客户信息,但是当然,它们不包含有关其会话数据的任何信息。

我现在的问题如下:

  1. 假设用户发出 HTTP 请求以发送消息,并且我的路由中的处理程序如下所示:

    export.sendMessage = function(req, res){ //在这里做事 };

我怎样才能让它在我的 socket.io 中“触发”某些东西来发送消息?我不想知道所有需要完成的底层工作,比如跟踪消息、用户等。我只想了解如何“触发”socket.io 来做某事。

  1. 如何确保 socket.io将消息发送给特定的人,并 100% 确保没有其他人收到它?据我所知,没有办法从 sIo 对象获取会话信息。

提前致谢。

4

2 回答 2

3

问题一:将两者分开的最干净的方法可能是使用EventEmitter。您创建一个 EventEmitter,它在 http 消息进入时发出。您可以将会话信息与事件一起传递,以便在必要时将其绑定回发送消息的用户。

// index.js (./routes)
var EventEmitter = require('events').EventEmitter;

module.exports.messageEmitter = messageEmitter = new EventEmitter();

module.exports.sendMessage = function(req, res) {
  messageEmitter.emit('private_message', req.params.recipient, req.params.text);
};

问题2:你可以在初始连接时访问套接字。一个主要从这个答案借来的例子:

var connect = require('connect'),
    userMap = {};

routes.messageEmitter.on('private_message', function(recipient, text) {
    userMap[recipient].emit('private_message', text);  
});

io.on('connection', function(socket_client) {
  var cookie_string = socket_client.request.headers.cookie;
  var parsed_cookies = connect.utils.parseCookie(cookie_string);
  var connect_sid = parsed_cookies['connect.sid'];
  if (connect_sid) {
    session_store.get(connect_sid, function (error, session) {
      userMap[session.username] = socket_client;
    });
  }

  socket_client.on('private_message', function(username, message) {
      userMap[username].emit(private_message, message)
  });
});

所以我们只是在会话的用户名和套接字连接之间创建一个映射。现在,每当您需要发送消息时,您都可以轻松查找与该用户关联的套接字并使用他们的套接字向他们发送消息。只需确保在多个选项卡中处理断开连接、重新连接和连接等。

于 2013-08-14T19:16:01.380 回答
0

我已经建立了像你所说的那样的东西。如果用户可以发出套接字请求,它会通过套接字推送消息,然后服务器进行广播或发射。但是,如果用户无法连接到套接字,它就会执行 http 发布,就像您通过调用 sendMessage 所说的那样。我所做的,而不是让 sendMessage 从套接字发射,我还让我的客户每 5 秒左右执行一个 ajax 请求。这将带回新消息,如果没有通过 socket.io 接收到任何消息,我会将它们添加到我的客户端数组中。这就像一个安全网,所以我不必总是完全信任 socket.io。

见下面的伪代码

客户

if canSendSocketMessage()
  sendSocketMessage(message)
else
  sendAjaxMessage(message)

setInterval( ->
  // ajax call
  getNewMessages()
), 5000

服务器

插座的东西

socket.on 'message' ->
   saveMessage()
   socket.emit(message)

ajax 端点

 app.post 'sendMessage'
    saveMessage()

 app.get 'getNewMessages'
    res.send getNewMessages()
于 2013-08-14T18:53:25.147 回答