在 node.js 中与 socket.io 私聊

Posted

技术标签:

【中文标题】在 node.js 中与 socket.io 私聊【英文标题】:private chat with socket.io in node.js 【发布时间】:2016-05-21 22:02:50 【问题描述】:

我正在尝试创建一个聊天系统,用户可以在其中向所有人发送消息(并且此消息显示在 id 为“chat”的 div 中)并且我已经实现了此功能。现在我想实现一个私人聊天。用户可以在右栏中单击另一个用户的名称(显示所有登录的用户),一旦他单击用户名,就会出现一个小窗口(带有“chatpopup”类的div),在这个窗口中有一个提交按钮和一个输入要填充消息的文本,单击提交按钮后,应将消息发送给其他用户。

这就是我所拥有的,如果我单击用户(在屏幕右侧),则会显示小窗口(chatpopup),但是当我尝试在这个小窗口内提交表单时,应用程序会崩溃。 我还想收到一些关于建立私人聊天的提示,例如如何在应该接收消息的用户的客户端打开一个新窗口(带有消息接收)?

index.html

<html>
<head>
    <title>Chat with socket.io and node.js</title>
    <style>
        #contentWrap
        
            width:100%;
            display: none;
        
        #chatWrap float: left; width:80%;
        #chat
        
            height:500px;
            width:96%;
            border: 1px #000 solid;
            padding-left:2%;
            padding-right:2%;
        
        #users 
        
            margin-left:82%; width:15%;
            height:500px; 
            border: 1px #000 solid; 
            text-align:right;
        
        #send-message margin-top:3%; width:100%;
        #message width:80%;
        .err1r padding-top:1%;
            color: red;
        
        .whisper
            color: gray;
            font-style: italic;
        
        p.sideusername:nth-child(even) background-color:#FAFAFA; padding-bottom:5%; padding-top:5%;
        p.sideusername:nth-child(odd) background-color: #f5f5f0; padding-bottom:5%; padding-top:5%;
        .chatpopup width:350px; height: 250px; background-color:blue;
        #interlocutore background-color:red; height: 30px; text-align: left;
        #msgspace height:150px; background-color:yellow;
    </style>
</head>
<body>
    <div id="nickWrap">
        <p>Enter a username:</p>
        <p id="nickError"></p>
        <form id="setNick">
            <input size="35" id="nickname"></input>
            <input type="submit"></input>
        </form>
    </div>

    <div id="contentWrap">
        <div id="chatWrap">
            <div id="chat"></div>
            <form id="send-message">
                <input size="35" id="message"></input>
                <input type="submit"></input>
            </form>

        </div>
        <div id="users"></div>
    </div>


    <script src="http://code.jquery.com/jquery-latest.min.js"></script>
    <script src="/socket.io/socket.io.js"></script>
    <script>
        jQuery(function($)
            var socket = io.connect();
            var $nickForm = $('#setNick');
            var $nickError = $('#nickError');
            var $nickBox = $('#nickname');
            var $users = $('#users');
            var $messageForm = $('#send-message');
            var $messageFormPopup = $('#send-message-popup');
            var $messageBox = $('#message');
            var $messageBoxPopup = $('#messagePopup');
            var $chat = $('#chat');

            $nickForm.submit(function(e)
                e.preventDefault();
                socket.emit('new user', $nickBox.val(), function(data)
                    if(data)
                        $('#nickWrap').hide();
                        $('#contentWrap').show();
                     else
                        $nickError.html('That username is already taken!  Try again.');
                    
                );
                $nickBox.val('');
            );

            socket.on('usernames', function(data)
                $users.empty();
                for(var i=0; i < data.length; i++)
                    $users.append('<p class="sideusername">' + data[i] + "</p>");   
                
            );

            $messageForm.submit(function(e)
            
                e.preventDefault();
                socket.emit('send message', $messageBox.val(), function(data)
                
                );
                $chat.append('<span class="error">' + data + "</span><br/>");
                $messageBox.val('');
            );

            $messageFormPopup.submit(function(e)
            
                e.preventDefault();
                socket.emit('send popup message', $messageBoxPopup.val(), function(dataPopup)
                

                );
                $messageBoxPopup.val('');
            );

            socket.on('load old msgs', function(docs)
                for(var i=docs.length-1; i >= 0; i--)
                    displayMsg(docs[i]);
                
            );

            socket.on('new message', function(data)
                displayMsg(data);
            );

            function displayMsg(data)
                $chat.append('<span class="msg"><b>' + data.nick + ': </b>' + data.msg + "</span><br/>");
            

            socket.on('whisper', function(data)
                $chat.append('<span class="whisper"><b>' + data.nick + ': </b>' + data.msg + "</span><br/>");
            );

            $(document).on("click", ".closepopup", function() 
                $(this).parents('.chatpopup').hide();
            );

            $(document).on("click", ".sideusername", function()
            
                var interlocutore = $(this).text();
                $chat.append('<div class="chatpopup"><table><tr><td id="interlocutore"></td><td><p class="closepopup">X</p></td></tr><tr><td colspan="2" id="msgspace"></td></tr><tr><td colspan="2"><form id="send-message-popup"> <input size="35" id="messagePopup"></input><input type="submit"></input></form></td></tr></table></div>');
                $('#interlocutore').append(interlocutore);
            );

        );
    </script>
</body>
</html>

app.js

    var express = require('express'),
    app = express(),

server = require('http').createServer(app),
io = require('socket.io').listen(server),
mongoose = require('mongoose'),
users = ;
server.listen(3000);

    mongoose.connect('mongodb://localhost/chat', function(err)
    
        if(err)
           console.log(err);
        else console.log('Connected to mongodb!');
    );

    var chatSchema = mongoose.Schema(
    
        nick: String,
        msg: String,
        created: type: Date, default: Date.now
    );

    var Chat = mongoose.model('Message', chatSchema);
    app.get('/', function(req, res)
    
        res.sendfile(__dirname + '/index.html');
    );

    io.sockets.on('connection', function(socket)
    
        var query = Chat.find();
        query.sort('-created').limit(8).exec(function(err, docs)
          // carico gli ultimi 8 messaggi in ordine di data
            if(err) throw err;
            socket.emit('load old msgs', docs);
        );

        socket.on('new user', function(data, callback)
        
            if (data in users)
                callback(false);
            else
            
                callback(true);
                socket.nickname = data;
                users[socket.nickname] = socket;
                updateNicknames();
            
        );


        function updateNicknames()
        
            io.sockets.emit('usernames', Object.keys(users));
        

        socket.on('send message', function(data, callback)
        
                var msg = data.trim();
                var newMsg = new Chat(msg: msg, nick: socket.nickname);
                newMsg.save(function(err)
                
                    if(err) throw err;
                    io.sockets.emit('new message', msg: msg, nick: socket.nickname);
                );

                socket.on('disconnect', function(data)
                
                    if(!socket.nickname) return;
                    delete users[socket.nickname];
                    updateNicknames();
                );
        );


        socket.on('send popup message', function(data, callback)
        
            /*var msgPopup = dataPopup.trim();
            if (msgPopup !== "")
                users[interlocutore].emit('whisper', msg: msgPopup, nick: socket.nickname);
            */
                var msg = data.trim()+" hello";
                var newMsg = new Chat(msg: msg, nick: socket.nickname);
                newMsg.save(function(err)
                
                    if(err) throw err;
                    io.sockets.emit('new message', msg: msg, nick: socket.nickname);
                );
            socket.on('disconnect', function(data)
            
                if(!socket.nickname) return;
                delete users[socket.nickname];
                updateNicknames();
            );
        );
    );

【问题讨论】:

你使用的是哪个版本的socket.IO? 【参考方案1】:

要使用 socket.IO 创建私人聊天,您需要首先了解 socket.IO 中的rooms 是如何工作的。你可以找到大量的教程。您也可以查看this 发帖寻求帮助。

现在您需要扩展此功能以创建私人聊天系统。为此,您需要为每个已连接或在线的客户端设置一个唯一的 idsocket.id 是每个客户在加入聊天时获得的唯一密钥。

在客户端,您可以将 name 连同消息一起发送到服务器。你这样做:

socket.emit('privateMessage', 'theUserName', message);

在服务器端,您可以管理一组已连接的用户并保存他们唯一的用户名或 id

var connectedClients = ;

因此,每次用户连接到聊天时(您可能正在使用new user 事件),将用户的ID 保存在connectedClients 中。

connectedClients[username] = socket.id;

其中username 是在用户连接到聊天系统时发送到服务器的名称。 (我希望你知道怎么做。如果不知道,请问我。)

然后我们创建一个监听器来监听privateMessage 事件并将消息发送给该特定用户,我们这样做:

socket.on('privateMessage', function(to, message) 
    var id = connectedClients[to];
    io.sockets.socket(id).emit('sendPrivateMessage', socket.username, message);
);

最后,在客户端,sendPrivateMessage 的侦听器收到消息,您可以相应地更新视图。

【讨论】:

【参考方案2】:

想法是服务器通过用户名保存连接到它的每个套接字:users[socket.nickname] = socket;

因此,每当用户向另一个用户发送消息时 - 您应该发出一个事件 - 将另一个用户的用户名发送给该用户 - 获取该用户的套接字并向他发出一条消息:

客户:

socket.emit('sendPrivate','someusername','message');
socket.on('privateMsg',function(from,msg)
 //write private message from user 'from'
);

服务器:

socket.on('sendPrivate',function(to,msg)
   users[to].emit('privateMsg',socket.username,msg);
);

【讨论】:

以上是关于在 node.js 中与 socket.io 私聊的主要内容,如果未能解决你的问题,请参考以下文章

Node.js 和 socket.io 的混淆

Node.js - Socket.io:socket.request 未定义

找不到Node.js /socket.io/socket.io.js express 4.0

node.js + socket.io:拍卖网站开发

Node.js + Socket.io 在套接字中存储数据

Node.js socket.io.js 未找到或 io 未定义