根据我的理解,socket.io服务器通过N个独立的套接字管理自身与N个客户端之间的N个连接,每个套接字都有自己的ID。
因此,打开两个标签时,您可以获得两个不同的ID。
然而,请考虑这个最小的例子:
的index.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"></html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<title>Stuffy Stuff</title>
</head>
<body>
<button id="btnA">A</button>
<script src="/socket.io/socket.io.js"></script>
<script src="app.js"></script>
</body>
index.js
var express = require('express');
var path = require('path');
var app = express();
var servercode = require('./server');
app.use(express.static(path.join(__dirname,'public')));
var server = require('http').createServer(app).listen(process.env.PORT || 8080);
var io = require('socket.io').listen(server);
io.on('connection', function (socket)
{
console.log('client ' + socket.id + ' connected');
servercode.init(io, socket);
});
app.js
;
jQuery(function($) // client-side code
{
socket = io.connect();
$(document).on('click', '#btnA', stuff);
function stuff()
{
socket.emit('dostuff', socket.id);
socket.on('answerstuff', function()
{
console.log("Answered");
});
}
}($));
server.js
// Server-side
var io;
var socket;
exports.init = function(sio, sock)
{
io = sio;
socket = sock;
socket.on('dostuff', doStuff);
};
function doStuff(idd)
{
console.log('who is asking: ' + idd);
console.log('who am I answering to: ' + socket.id);
console.log(socket.id);
socket.emit('answerstuff');
}
现在说我启动node index.js
,然后打开localhost:8080
的两个实例;让我们称他们为A和B.如果我按下A&A实例上的按钮,那就是&#39; dostuff&#39;消息被发出,它被服务器捕获,但它回答的套接字是相对于B实例的套接字,而不是A&#39。一般来说,它回答了最新的实例。为什么会这样?
编辑:解释 当我终于掌握了我的错误的本质时,我想我可以帮助遇到类似问题的人。
让我们来看看我们的示例工作流程:A连接,B连接,A按下按钮。
server.init(io, socket A)
被称为init(socket A)
将带有回调函数dostuff
的{{1}}事件附加到套接字A doStuff
将init
附加到套接字B dostuff
通过套接字A的ID dostuff
已执行,但其定义包含对未在函数范围内定义的变量(doStuff(idd)
)的引用,因此必须导航其父作用域socket
(如果我们省略socket = sock
,声明会在范围内冒泡,直到找到具有此名称的变量为止如果我们写了var
INSIDE var socket = sock
,那么函数就找不到任何这样的变量了)
init
再次执行,socket
指向套接字B.因此,该函数只知道套接字B。为了解决这个问题,我们需要使用闭包:在定义时封装世界状态的函数。换句话说,闭包是一个包含函数定义的对象和不在函数作用域中但由它引用的变量的值。
正如JagsSparrow给出的解决方案所示,有两种方法可以解决这个问题,并且都涉及创建一个闭包:
1。使用init
功能
function.bind(thisArg, args)
函数返回函数&#39; A&#39;调用bind()
绑定到this
的位置(通常指向调用A的对象)并实例化thisArg
中指定的任何参数。
在我们的案例中,我们不需要args
,因为它在this
函数中从未提及,但我们确实需要它来记住哪个套接字是在参数。我们可以通过写
doStuff()
此表达式返回一个doStuff.bind(null, socket)
函数的对象,在其上下文中doStuff()
等于this
(我们可以写null
:在那里case,doStuff.bind(this, socket)
等于this
),其第一个参数init
绑定到socket
。因此,
socket
告诉套接字A在socket.on('dostuff', doStuff.bind(this,socket));
发生时触发doStuff
(包含对套接字A的引用)。与套接字B和任何其他套接字相同。
2。使用嵌套函数
我们只是在dostuff
内移动function doStuff(idd)
的定义:
socket.on()
这样,套接字再次绑定到一个函数,该函数包含(通过闭包)任何执行此操作的套接字的定义。
答案 0 :(得分:1)
在server.js
中,您声明var socket;
本地服务器.js模块(模块范围),
因此,每次连接时,此变量都会分配给不同的客户端
socket
时,客户端A。socket
是客户端B。所以,不要将socket
变量置于server.js模块的本地变量
解决方案1: 的 server.js 强>
var io;
//var socket;
exports.init = function(sio, sock)
{
io = sio;
socket = sock;
socket.on('dostuff', doStuff.bind(this,socket));
};
function doStuff(socket,idd)
{
console.log('who is asking: ' + idd);
console.log('who am I answering to: ' + socket.id);
console.log(socket.id);
socket.emit('answerstuff');
}
解决方案2: 的 server.js 强>
var io;
//var socket;
exports.init = function(sio, sock)
{
io = sio;
var socket = sock;
socket.on('dostuff', function doStuff(idd)
{
console.log('who is asking: ' + idd);
console.log('who am I answering to: ' + socket.id);
console.log(socket.id);
socket.emit('answerstuff');
});
};