Websocket-突然下降后重新建立连接
我开发了一个使用websocket连接的小型数据库系统。 有时连接可能会突然中断,而不是因为电缆或电力问题,我现在不清楚原因 我增加了心跳,每3秒检查一次连接,在服务器端,我给连接超时5秒,以防连接突然变慢 问题: 在客户端意识到连接丢失后,它将尝试重新连接。有时它能工作,但有时它会反复失败——也许是因为连接断开了???怎么会?在重新连接之前,我正在尝试确保连接完全关闭。我做错了什么 JS来源(部分):Websocket-突然下降后重新建立连接,websocket,Websocket,我开发了一个使用websocket连接的小型数据库系统。 有时连接可能会突然中断,而不是因为电缆或电力问题,我现在不清楚原因 我增加了心跳,每3秒检查一次连接,在服务器端,我给连接超时5秒,以防连接突然变慢 问题: 在客户端意识到连接丢失后,它将尝试重新连接。有时它能工作,但有时它会反复失败——也许是因为连接断开了???怎么会?在重新连接之前,我正在尝试确保连接完全关闭。我做错了什么 JS来源(部分): EF.WS=new EF_WebSocketInterface(); 函数EF_WebSoc
EF.WS=new EF_WebSocketInterface();
函数EF_WebSocketInterface(){
var=this,QS={},QR={},ito,hb;
window.onunload=function(){
如果(!| |!|.con)返回;
//向服务器发送终止命令
}
_.Init=函数(p,f){Run(f);}
函数运行(f){
if(&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&;
如果(!hb)hb=setInterval(u.SMInt,3000,“-”,“);//心跳
}
试一试{
_.con=new WebSocket('wss://'+document.domain+':'+/*端口*/+'/?C='+/*凭据已检查为OK*/+'&L=EN-US');
_.con.onerror=函数(e){console.log(e);}
_.con.onopen=function(){{{uu.con.tmt=Date.now();}
_.con.onclose=function(){setTimeout(Run,1);}//立即重新连接!
_.con.onmessage=函数(e){
var V=new FileReader(),C,I;
_.con.tmt=Date.now();//来自服务器的任何输入消息(包括心跳信号)都在更新时间戳!
V.addEventListener(“loadend”,函数(){
V=V.result.replace(/\n/g')。replace(/\r/g');
if(V='-')返回;//忽略服务器心跳信号进行处理。
/*消息(命令)处理*/
});
V.readAsText(即数据);
}
}
catch(e){console.log(e);if(u.con)u.con.onclose();}
}
/*这是发送命令的官方功能。
这将在特殊队列中为案例连接丢失注册消息,以便在不重复用户交互的情况下重新发送它们。
参数:
p=命令代码
c=命令内容的参数
f=接收消息时要执行的函数回调(可选)
x=保留供内部使用
*/
_.SM=函数(p,c,f,x){
变量d=“”+(QS.++);而(d.长度1,
on_tick=>sub{
my@l=keys%CON;#这是主连接数据库,每个数据库都有自己的属性
我的$i;我的$j;我的@m;
$\u TPC->[2]+;如果($\u TPC->[2]==5){$\u TPC->[2]=0;}
如果($\u TPC->[2]==0){
对于($i=0;$ireq->资源名称;
我的$ns=substr($nsn,4,索引($nsn,&L=')-4);
$cid=($ns eq“”)?整数(兰特(100000000)):$ns;
如果(!defined$CON{$cid}){$CON{$cid}={“QS”=>0},“QR”=>{},“T”=>time(),“L”=>substr($nsn,index($nsn,&L=')+3)}
elsif(定义为$CON{$cid}{“C”}){$CON{$cid}{“C”}->disconnect();}
$CON{$cid}{“C”}=$conn;
},
二进制=>sub{
#对于任何输入消息-更新活动时间戳。
$CON{$cid}{“T”}=time();my$c$msg)=@;
#忽略客户端心跳
if($msg eq'-'){return;}
#处理消息(命令)
},
断开连接=>sub{}#没有什么特别的事情要做。
);
}
)->开始;
子CX{
$CON{$\[0]}{“C”}->disconnect();
删除$CON{$\[0]}{“C”};如果($\[1]==1&&$CON{$\[0]}{'U'}eq”“){&XX($\[0]);}
}
sub XX{删除$CON{$\[0]};}
注意:
1.作为JS变量存储在客户端的凭据不会丢失,除非客户端刷新浏览器,但情况并非如此。2.在这样的“连接断开”上检查的readystate变量仍然显示1-但是消息没有被转发到服务器。
3.在重复连接失败的情况下,如果我刷新浏览器并重新连接,它将正常工作(奇怪…)。 4.在PERL中,如果有帮助的话,我将使用Net::Websocket::Server和IO::Socket::SSL PERL命令断开与连接的连接是否可能需要更长的时间才能关闭? 任何关于连接突然中断或我无法重新连接的想法都将不胜感激
EF.WS=new EF_WebSocketInterface();
function EF_WebSocketInterface() {
var _=this,QS={_:0},QR={},ito,hb;
window.onunload=function() {
if(!_||!_.con) return;
// send termination command to the server
}
_.Init=function(p,f) { Run(f); }
function Run(f) {
if(_.con&&_.con.readyState!==3) return setTimeout(Run,1,f);
if(!hb) hb=setInterval(_.SMInt,3000,'-',''); // Heartbeat
}
try {
_.con=new WebSocket('wss://'+document.domain+':'+/* port */+'/?C='+ /* credentials been checked as OK */+'&L=EN-US');
_.con.onerror=function(e) { console.log(e); }
_.con.onopen=function() { _.con.tmt=Date.now(); }
_.con.onclose=function() { setTimeout(Run,1); } // immediate reconnection!
_.con.onmessage=function(e) {
var V=new FileReader(),C,I;
_.con.tmt=Date.now(); // Any incomming messages from the server including the heartbeat are updating the time stamp!
V.addEventListener("loadend", function() {
V=V.result.replace(/\n/g,'').replace(/\r/g,'');
if(V=='-') return; // ignore server heartbeat for processing.
/* Message (command) processing */
});
V.readAsText(e.data);
}
}
catch(e){ console.log(e); if(_.con) _.con.onclose(); }
}
/* This is the official function to send commands.
This will register the message in special queue for a case connection lost, to resend them without repeated user interaction.
Parameters:
p = Command code
c = Parameters content for command
f = function callback to be done on message receive (optional)
x = reserved for internal use
*/
_.SM=function(p,c,f,x) {
var d=""+(QS._++); while(d.length<5) d="0"+d; QS[d]=[(x?"":EF.ON([p,c])),Date.now(),f]; _.SMInt((x?x:"A"),d);
}
/* This is internal command sender*/
_.SMInt=function(b,c) {
/* Command preparation and message ID management */
// Preparation for sending the message
if(_.con&&_.con.readyState==1)
// If pass more than 5 seconds, the connection probably closed.
if(_.con.tmt+5000<Date.now()) { _.con.close(); }
else {
// Sending of heartbeat to the server, also checking if has got any pending messages in queue since last failed session.
if(b=='-') {
if(ito) return; ito=1; var n=Object.keys(QS);
for(var i=0 ; i<n.length ; i++) if(n[i]!=='_' && QS[n[i]][1]+5000<Date.now()) _.SMInt("C",n[i]);
ito=0;
}
try { _.con.send(new Blob([m],{type:'text/html',charset:'utf-8'}),{ binary:true }); }
catch(e) { }
}
}
_.Get=function(p,m,r,c) { _.SM(m,r,function(e) { _.xQ(p,EF.Data,e); c(); });
}
}
Net::WebSocket::Server->new(
listen => $ssl,
silence_max=> 14400,
tick_period => 1,
on_tick => sub {
my @l=keys %CON; # This is the main connections DB, each with its own properties
my $i; my $j; my @m;
$_TPC->[2]++; if($_TPC->[2]==5) { $_TPC->[2]=0; }
if($_TPC->[2]==0) {
for($i=0 ; $i<@l ; $i++) {
# Resend pending messages in queue
# If connection passed 10 seconds without any message, it is clearly lost: &CX is closing the connection and deleting the session from %CON.
if($CON{$l[$i]}{"C"}) {
if($CON{$l[$i]}{"T"}+10<time()) { &CX($l[$i],($CON{$l[$i]}{"T"}+300<time())?1:0); }
else { &SMInt($l[$i],'-',''); }
}
elsif($CON{$l[$i]} && $CON{$l[$i]}{"T"}+14400<time()) { &XX($l[$i]); }
}
},
on_connect => sub {
my($serv,$conn)=@_; my $cid;
$conn->on(
handshake => sub {
my($conn,$handshake)=@_;
my $nsn=$handshake->req->resource_name;
my $ns=substr($nsn,4,index($nsn,'&L=')-4);
$cid=($ns eq "")?int(rand(1000000000)):$ns;
if(!defined $CON{$cid}) { $CON{$cid}={"QS"=>{"_"=>0},"QR"=>{},"T"=>time(),"L"=>substr($nsn,index($nsn,'&L=')+3)}; }
elsif(defined $CON{$cid}{"C"}) { $CON{$cid}{"C"}->disconnect(); }
$CON{$cid}{"C"}=$conn;
},
binary => sub {
# for any incomming messages - update the active time stamp.
$CON{$cid}{"T"}=time(); my($c,$msg)=@_;
# ignore client side heartbeat here
if($msg eq '-') { return; }
# Process the message (command)
},
disconnect => sub {} # Nothing special to be done.
);
}
)->start;
sub CX {
$CON{$_[0]}{"C"}->disconnect();
delete $CON{$_[0]}{"C"}; if($_[1]==1 && $CON{$_[0]}{'U'} eq "") { &XX($_[0]); }
}
sub XX { delete $CON{$_[0]}; }