在 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 发帖寻求帮助。
现在您需要扩展此功能以创建私人聊天系统。为此,您需要为每个已连接或在线的客户端设置一个唯一的 id。 socket.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:socket.request 未定义