我正在尝试防止Socket.io客户端由于心跳超时而断开与服务器的连接,因为我的客户端花了太多时间来操作DOM。
通常,Socket.io超时对于我的应用程序来说非常合适。在一个实例中,客户端可能想要生成一张他们正在使用的数据表。数据大小可变,具体取决于客户端使用的是哪个数据集,因此它可能很小(这不是问题)或很大。我关注的是数据何时如此之大,以至于它会导致Socket.io心跳超时。
由于数据是可变长度的,并且是在初始化客户端/服务器连接之后选择的,因此我需要能够动态地控制发生超时所允许的时间。换句话说,由于除此 one 特定实例外,超时通常很好,因此我想根据DOM操作的进行方式来增加超时所允许的时间,并将其重置为DOM操作完成后正常超时。
这里有一些额外的信息,那就是我服务器的断开连接代码会杀死生成的Python进程来处理一些繁重的数据计算。此过程与该特定客户端相关。因此,如果客户端/服务器通信中断,则客户端与此Python进程的通信也将中断,这意味着如果客户端无法维持与服务器的连接,则该客户端实际上是无用的。这意味着简单的“重新连接”是不够的(除非我可以在服务器决定终止Python进程之前将其重新连接到同一Socket.io房间/会话)。
有人知道如何正确动态地操作Socket.io心跳超时吗?还是我可以通过长时间的DOM操作来避免超时?如果有一种方法可以在不使客户端挂起并保持生成表的交互性的情况下执行此DOM操作,则额外的好处! / p>
代码/浏览器版本:
- Node.js:8.16.2(我知道它很旧,但是我们所依赖的软件包与Node.js的较新版本不兼容)
- socket.io:^2.2.0
- d3:3.5.17(?)
- 我到d3的链接是http://d3js.org/d3.v3.min.js,我知道它已经很旧了,但是我记得曾经尝试升级一次,这使所有内容都无法正常工作,所以我不敢更改,因为那将意味着更新数千行代码在我的整个应用中
- JQuery:1.12.1(我知道它也很旧)
- Chrome:78.0.3904.70(正式版本)(64位)
我尝试过的东西:
- 使用for循环将表单转换为使用forEach函数来迭代要解析的数据以创建表(因为我的一个朋友建议这样做可能会让我心跳加速一些,但我没有注意到有所不同)
- 使用setTimeout尝试允许客户端有足够的时间发送/接收心跳消息(我测试了长达1s的超时,我认为应该足够大以保持心跳)
- 使用异步函数尝试有效地使并行线程运行(我希望其中一个可以处理心跳)
- 使用
socket.emit("ping")
,socket.emit("pong")
或我自己的socket.emit("heartbeat")
发出心跳信号
- 试图操纵服务器的io对象的属性以在触发超时之前强制允许更长的时间(如果有办法,我找不到合适的办法)
- 试图动态禁用客户端和服务器的断开连接功能(这似乎没有效果;请参见下面的代码)
这是我在客户端上引起该问题的代码(我最近尝试尝试禁用“断开连接”消息的影响):
var shouldDisconnect = true;
socket.on('disconnect',disconnectFunc(shouldDisconnect));
function disconnectFunc(shouldDisconnect) {
return function() {
if (shouldDisconnect) {
d3.selectAll("div").remove();
d3.select("body").append("h3").text("Your communication with the server " +
"has been interrupted. Please refresh this page to reconnect.");
}
}
}
// Similar logic in manipulating a shouldDisconnect variable and the
// socket.on("disconnect") callbacks is repeated server-side. This
// approach doesn't seem to have any effect on when I see timeouts.
// Prevent the server from disconnecting
shouldDisconnect = false;
socket.removeListener("disconnect",disconnectFunc(shouldDisconnect));
socket.on("disconnect",disconnectFunc(shouldDisconnect));
socket.emit("setDiconnect",false);
// Create a table of the raw CSV data that we have been provided
var rawDataDiv = rawTableContainer.append("div")
.attr("id","rawDataDiv")
.attr("class","col-md-12")
.style("width",function () {
return (this.parentNode.clientWidth - 60) + "px";
})
.style("height","500px")
.style("border","solid black 1px")
.style("margin","15px 20px 15px")
.style("overflow","scroll");
var rawDataTable = rawDataDiv.append("table")
.attr("id","rawDataTable")
.attr("class","table");
// Sort the keys,leaving the specified key as the first key
var dataKeys = Object.keys(csvContents[0]);
dataKeys.splice(dataKeys.indexOf(firstKey),1);
dataKeys = [firstKey].concat(dataKeys.sort());
// Sort the objects
csvContents.sort((a,b)=> (a[dataKeys[0]] > b[dataKeys[0]]) ? 1 : -1 );
// Create the first row of the table
var firstRow = rawDataTable.append("thead").append("tr");
var i;
for (i = 0; i < dataKeys.length; i++) {
firstRow.append('th').attr("scope","col").append("p").text(dataKeys[i]);
}
// Create each individual row of the table
rawDataTable = rawDataTable.append("tbody");
csvContents.forEach(async function(csvRow) {
var nextRow = rawDataTable.append("tr")
// Highlight row when mousing over
.on("mouseover",function() {
d3.select(this).classed("selected-row",true)
.selectAll("td").style("background-color","yellow");
})
.on("mouseout",false)
.selectAll("td").style("background-color","white");
});
// Create each entry for the current row
dataKeys.forEach(async function(dataKey,i) { setTimeout( function() {
var td;
if (dataKey === dataKeys[0]) {
td = nextRow.append("th").attr("scope","row");
}
else {
td = nextRow.append('td')
// Highlight column when mousing over
// Code adapted from https://stackoverflow.com/questions/38131000/how-to-highlight-a-column-in-html-table-on-click-using-js-or-jquery
.on("mouseover",function() {
var index = $(this).index();
$("#rawDataTable tr").each(function(i,tr) {
$(tr).find('td').eq(index-1).css("background-color","yellow");
});
})
.on ("mouseout",function() {
var index = $(this).index();
$("#rawDataTable tr").each(function(j,tr) {
$(tr).find('td').eq(index-1).each(function(k,td) {
if (!$(tr).hasClass("selected-row")) {
$(td).css("background-color","white");
}
});
});
});
// Add an ID and tooltip for each td
var observationName = csvRow[firstKey];
td.attr("id","o-" + observationName.replace(/\/|<|>|\.| |'/g,"-") + "--a-" + dataKey.replace(/\/|<|>|\.| |'/g,"-")).attr("title",observationName + "," + dataKey);
}
td.append("p").text(csvRow[dataKey]);
},200) });
});
socket.removeListener("disconnect",disconnectFunc(shouldDisconnect));
shouldDisconnect = true;
socket.on("disconnect",true);