Websocket-突然掉线后重新建立连接

时间:2018-06-20 02:59:25

标签: websocket

我开发了一个使用websocket连接的小型数据库系统。 有时连接可能突然断开,而不是因为电缆或电力问题,原因现在我不清楚。

我添加了心跳信号,每3秒检查一次连接,在服务器端,如果连接突然突然变慢,我给出5秒的连接超时。

问题: 客户端意识到连接丢失后,它将尝试重新连接。有时它可以工作,但有时会反复失败-也许是因为打开的连接???怎么来的?我试图确保重新连接之前连接已完全关闭。我做错了吗?!

JS源(部分):

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(); }); 
}
}

https://www.crazygao.com/ef4中可用的完整JS代码

服务器端PERL(部分):

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]}; }

注意: 1.除非客户端将刷新浏览器,否则不会丢失作为JS变量存储在客户端的凭据,但这不是这种情况。
2.在此类“连接断开”上检查的readystate变量仍显示1-但消息未转发到服务器。
3.在反复出现连接故障时,如果刷新浏览器并重新连接,它将可以正常工作(奇怪...)。 4.在PERL中,如果有帮助,我正在使用Net :: Websocket :: Server和IO :: Socket :: SSL。

断开连接的PERL命令是否可能需要更长的时间才能关闭? 对于突然断开连接或为什么我无法重新连接的任何想法,将不胜感激。

0 个答案:

没有答案