Javascript 通过 socket.id 向客户端发送消息

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8467784/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 06:07:15  来源:igfitidea点击:

Sending a message to a client via its socket.id

javascriptnode.jssocket.io

提问by Hyman

I can only seem emit messages to users when their socket id has been directly stored within the io.sockets.on('connect') function. I don't know why it doesn't work when trying to store their socket id after they have logged in.

当用户的套接字 ID 直接存储在 io.sockets.on('connect') 函数中时,我似乎只能向用户发送消息。我不知道为什么在他们登录后尝试存储他们的套接字 ID 时它不起作用。

Working:

在职的:

  var clients = {};
  /** A new socket connection has been accepted */
  io.sockets.on('connection', function (socket)
  {
    //Used to access session id
    var hs = socket.handshake;            
        clients[socket.id] = socket; // add the client data to the hash   
        users['brownj2'] = socket.id; // connected user with its socket.id

    socket.on('user-login', function(user){
      if(!users[username]){
        //users[username] = socket.id; // connected user with its socket.id
      }
    })

    socket.on('page-load', function(pid)
    {
      if(users['brownj2'])
      {        
        clients[users['brownj2']].emit('hello');
      }
      else
      {
        console.log("NOT FOUND BROWNJ2");
      }
    }
  }

Not working:

不工作:

  var clients = {};
  /** A new socket connection has been accepted */
  io.sockets.on('connection', function (socket)
  {
    //Used to access session id
    var hs = socket.handshake;            
        clients[socket.id] = socket; // add the client data to the hash            

    socket.on('user-login', function(user){          
      if(!users['brownj2']){
        users['brownj2'] = socket.id; // connected user with its socket.id
      }
    })

    socket.on('page-load', function(pid)
    {
      if(users['brownj2'])
      {        
        clients[users['brownj2']].emit('hello');
      }
      else
      {
        console.log("NOT FOUND BROWNJ2");
      }
    }
  }

JavaScript Client-side code snippet

JavaScript 客户端代码片段

var socket = io.connect('');
socket.on("hello", function(){
  alert("Hi Hyman");
  console.log("WEBSOCKET RECIEVED");
})

Solution: Thanks @alessioalexI have had to remove the reference to socket.io from the login page, and add the following into io.sockets.on('connection')

解决方案:谢谢@alessioalex我不得不从登录页面中删除对 socket.io 的引用,并将以下内容添加到 io.sockets.on('connection')

var hs = socket.handshake;

sessionStore.get(hs.sessionID, function(err, session){
  console.log("SESSION: " + util.inspect(session));

  clients[socket.id] = socket; // add the client data to the hash
  validUsers[session.username] = socket.id; // connected user with its socket.id
})

回答by alessioalex

There are some problems with your code, the first being you shouldn't authenticate users through Socket.IO, you should make sure they can connect only after they authenticated. If you are using Express, then the following article can help you a lot: http://www.danielbaulig.de/socket-ioexpress/

您的代码存在一些问题,首先是您不应该通过 Socket.IO 对用户进行身份验证,您应该确保他们只能在通过身份验证后才能连接。如果您使用的是 Express,那么下面的文章可以帮到您很多:http: //www.danilbaulig.de/socket-ioexpress/

Also you should be avoiding sending messages like so, since that is part of Socket.IO internally and may change:

你也应该避免像这样发送消息,因为它是 Socket.IO 内部的一部分并且可能会改变:

io.sockets.socket(id).emit('hello');

Instead (if you want to send a message to a specific client) it's better to keep an object for example with the connected clients (and remove the client once disconnected):

相反(如果您想向特定客户端发送消息)最好保留一个对象,例如连接的客户端(并在断开连接后删除客户端):

// the clients hash stores the sockets
// the users hash stores the username of the connected user and its socket.id
io.sockets.on('connection', function (socket) {
  // get the handshake and the session object
  var hs = socket.handshake;
  users[hs.session.username] = socket.id; // connected user with its socket.id
  clients[socket.id] = socket; // add the client data to the hash
  ...
  socket.on('disconnect', function () {
    delete clients[socket.id]; // remove the client from the array
    delete users[hs.session.username]; // remove connected user & socket.id
  });
}

// we want at some point to send a message to user 'alex'
if (users['alex']) {
  // we get the socket.id for the user alex
  // and with that we can sent him a message using his socket (stored in clients)
  clients[users['alex']].emit("Hello Alex, how've you been");
}

Sure, io.sockets.socket(id)may work (didn't actually test), but also it can be always changed as it's part of the Socket.IO internals, so my solution above is more 'safe'.

当然,io.sockets.socket(id)可以工作(实际上没有测试),但它也可以随时更改,因为它是 Socket.IO 内部的一部分,所以我上面的解决方案更“安全”。

Another thing you may want to change in your code on the client side is var socket = io.connect('');with var socket = io.connect('http://localhost');, as we can see in the official example of Socket.IO here: http://socket.io/#how-to-use

您可能希望在客户端的代码中更改的另一件事是var socket = io.connect('');使用var socket = io.connect('http://localhost');,正如我们在 Socket.IO 的官方示例中所见:http://socket.io/#how-to-use

回答by Hyman

I can see that this post is generating quite a lot of interest... so i'm going to post the code I used to implement this:

我可以看到这篇文章引起了很多人的兴趣......所以我要发布我用来实现这个的代码:

Notes

笔记

I have used Redis as the session storage. The session is initially setup during the login page via a HTTP request containing the users details, if these details are valid (Checked against a MongoDB document)... then the session is created.

我使用Redis作为会话存储。会话最初是在登录页面期间通过包含用户详细信息的 HTTP 请求设置的,如果这些详细信息有效(根据 MongoDB 文档检查)...然后创建会话。

Server Side Code Creation and Removal of Session / Socket

服务器端代码创建和删除会话/套接字

//Auth the user
io.set('authorization', function (data, accept) {
  // check if there's a cookie header
  if (data.headers.cookie) {
    data.cookie = parseCookie(data.headers.cookie);
    data.sessionID = data.cookie['express.sid'];

    //Save the session store to the data object
    data.sessionStore = sessionStore;

    sessionStore.get(data.sessionID, function(err, session){
      if(err) throw err;

      if(!session)
      {
        console.error("Error whilst authorizing websocket handshake");
        accept('Error', false);
      }
      else
      {
        console.log("AUTH USERNAME: " + session.username);
        if(session.username){
          data.session = new Session(data, session);
          accept(null, true);
        }else {
          accept('Invalid User', false);
        }
      }
    })
  } else {
    console.error("No cookie was found whilst authorizing websocket handshake");
    return accept('No cookie transmitted.', false);
  }
});

/** A new socket connection has been accepted */
io.sockets.on('connection', function (socket)
{    
  var hs = socket.handshake;
  if(hs.session)
  {
    if(hs.session.username)
    {
        clients[socket.id] = socket; // add the client data to the hash
        validUsers[hs.session.username] = socket.id; // connected user with its socket.id
    }
  }


  socket.on('disconnect', function()
  {
    delete browsing[hs.session.username]; //Remove the client from the browsing hash
    delete clients[socket.id];         // remove the client from the array
    delete validUsers[hs.session.username]; // remove connected user & socket.id
  })
....
}

Server Side Selective Message Sending

服务器端选择性消息发送

This code allows me to send a message to team members of a project. A team of users won't receive messages from a separate team of users..

此代码允许我向项目的团队成员发送消息。一组用户不会收到来自另一组用户的消息。

for(var i = 0; i < project.team.length; i++)
{
  if(validUsers[project.team[i].username])
  {
    if(clients[validUsers[project.team[i].username]])
    {
      projects.update({"_id" : projectId},
        {"$pull" :
          {"stories" : {"_id" :  storyId}}
        }
      );                
      clients[validUsers[project.team[i].username]].emit('delete-story', storyId); 
    }
    else
    {
      console.error("Project team member not found");
    }
  }
}