Sunucu WebSocket'te yeniden başlatıldığında İstemcinin yeniden bağlanması


96

İstemci olarak PHP5 ve Chrome tarayıcısını kullanan web soketini kullanıyorum. Kodu http://code.google.com/p/phpwebsocket/ sitesinden aldım .

Sunucuyu çalıştırıyorum ve istemci de bağlı. Ben de sohbet edebilirim. Şimdi sunucuyu yeniden başlattığımda (onu öldürüp yeniden başlatarak), istemci bağlantısı kesilen bilgileri alıyor, ancak mesajı gönderdiğimde sunucuya otomatik olarak yeniden bağlanmıyor.

Bunu nasıl başarabilirim? Bağlantı kesilen bilgileri aldığım zaman olduğu gibi, sayfayı yenilemek veya yeniden bağlanmak için kontrol edip JavaScript'e göndermeli miyim?

Yanıtlar:


144

Sunucu yeniden başlatıldığında, Web Soketi bağlantısı kapatılır, bu nedenle JavaScript oncloseolayı tetiklenir. İşte her beş saniyede bir yeniden bağlanmaya çalışan bir örnek.

function start(websocketServerLocation){
    ws = new WebSocket(websocketServerLocation);
    ws.onmessage = function(evt) { alert('message received'); };
    ws.onclose = function(){
        // Try to reconnect in 5 seconds
        setTimeout(function(){start(websocketServerLocation)}, 5000);
    };
}

3
Yeni bir nesne oluşturmadan ve olay eylemlerini tanımlamadan daha zarif bir yol
olacağını umuyordum

3
5 dakika sonra tarayıcı donuyor. Tek kişi ben miyim?
Marc

17
"Ws = null;" eklemelisiniz çarpın nesneleri ve eventHandligs ws setTimeout () önlemek için önce
Max

8
Yanılıyorsam düzeltin, ancak bu kod biraz tehlikelidir çünkü belirli miktarda bağlantı kesilmesi yığın taşmasına neden olur. Bunun nedeni start, hiç geri dönmeden, yinelemeli olarak aramanızdır .
Forivin

11
@Forivin Burada yığın aşımı sorunu yok. Javascript'te herhangi bir anda kodumuzu çalıştıran tek bir iş parçacığı olduğundan, setTimeout () iletilen işlevi gelecekte o tek iş parçacığı tekrar serbest olduğunda çalıştırılacak şekilde planlar. SetTimeout () burada çağrıldıktan sonra, iş parçacığı işlevden geri döner (yığını temizler), ardından kuyruktaki bir sonraki olayı işleme koyar. Sonunda çağrıların başlatıldığı ve yığındaki üst çerçeve olarak adlandırılacak anonim işlevimize ulaşacaktır.
Kokmuş

41

Andrew tarafından verilen çözüm mükemmel çalışmıyor çünkü bağlantının kesilmesi durumunda sunucu birkaç yakın olay gönderebilir.

Bu durumda, birkaç setTimout ayarlayacaksınız. Andrew'un verdiği çözüm ancak sunucu beş saniyeden önce hazırsa işe yarayabilir.

Ardından, Andrew çözümünü temel alarak yeniden çalışarak, kimliği pencere nesnesine eklemek için setInterval kullandım (bu şekilde "her yerde" kullanılabilir):

var timerID=0;

var socket;

/* Initiate what has to be done */

socket.onopen=function(event){
 /* As what was before */
 if(window.timerID){ /* a setInterval has been fired */
   window.clearInterval(window.timerID);
   window.timerID=0;
 }
 /* ... */
}

socket.onclose=function(event){
  /* ... */
 if(!window.timerID){ /* Avoid firing a new setInterval, after one has been done */
  window.timerID=setInterval(function(){start(websocketServerLocation)}, 5000);
 }
 /* That way, setInterval will be fired only once after losing connection */
 /* ... */
}

setTimeout"global zamanlayıcı kimliği" fikrini onlara uygularsanız yine de kullanabilirsiniz ;)
RozzA

3
"Andrew tarafından verilen çözüm, ancak sunucu beş saniyeden önce hazırsa işe yarayabilir." - Bu ifade doğru değil. Sunucu beş saniye sonra hala kullanılamıyorsa, istemciniz bir WebSocket bağlantısını açamayacak ve oncloseolay yeniden başlatılacaktır .
Sourav Ghosh

36

Yeniden BağlanmaWebSocket

GitHub, bağlantı kesildiğinde otomatik olarak yeniden bağlanacak bir WebSocket bağlantısı sağlamak için WebSocket API'sini dekore eden küçük bir JavaScript kitaplığı barındırır.

Gzip sıkıştırmalı küçültülmüş kitaplık 600 bayttan azdır.

Resmi depoya buradan ulaşılabilir:

https://github.com/joewalnes/reconnecting-websocket

Sunucu taşması

Sunucu yeniden başlatıldığında sunucuya çok sayıda istemci bağlıysa. Bir Üstel Geri Alma algoritması kullanarak istemcilerin yeniden bağlanma zamanlamalarını yönetmek faydalı olabilir.

Algoritma şu şekilde çalışır:

  1. K deneme için, 0 ile 2 ^ k - 1 arasında rastgele bir zaman aralığı oluşturun,
  2. Yeniden bağlanabiliyorsanız, k'yi 1'e sıfırlayın,
  3. Yeniden bağlanma başarısız olursa, k 1 artar ve süreç 1. adımda yeniden başlar,
  4. Maksimum aralığı kesmek için, belirli sayıda k denemesine ulaşıldığında, k her denemeden sonra artmayı durdurur.

Referans:

http://blog.johnryding.com/post/78544969349/how-to-reconnect-web-sockets-in-a-realtime-web-app

ReconnectingWebSocket, bu algoritmayı kullanarak yeniden bağlantıları işlemez.


Harika yanıt, özellikle sunucu web soketi bağlantılarını kapattığında ve tüm istemciler (yüzlerce veya binlerce olabilir) aynı anda yeniden bağlanmaya çalıştığında yüksek sunucu yükü riskinden bahsettiği için. Üstel geri çekilme yerine, gecikmeyi 0 ile 10 saniye arasında rastgele hale de getirebilirsiniz. Bu, yükü sunucuya da yayacaktır.
Jochem Schulenklopper

29

Bu deseni saf vanilya JavaScript için bir süredir kullanıyorum ve diğer cevaplardan birkaç durumu daha destekliyor.

document.addEventListener("DOMContentLoaded", function() {

  'use strict';

  var ws = null;

  function start(){

    ws = new WebSocket("ws://localhost/");
    ws.onopen = function(){
      console.log('connected!');
    };
    ws.onmessage = function(e){
      console.log(e.data);
    };
    ws.onclose = function(){
      console.log('closed!');
      //reconnect now
      check();
    };

  }

  function check(){
    if(!ws || ws.readyState == 3) start();
  }

  start();

  setInterval(check, 5000);


});

Bu, sunucu bağlantıyı kapatır kapatmaz yeniden deneyecek ve her 5 saniyede bir açık olduğundan emin olmak için bağlantıyı kontrol edecektir.

Bu nedenle, sunucu çalıştırıldığında veya onclose etkinliği sırasında çalışmazsa, bağlantı tekrar çevrimiçi olduğunda yine de geri gelecektir.

NOT: Bu komut dosyasını kullanmak, bir bağlantı açmaya çalışmaktan asla vazgeçmenize izin vermez ... ama bence istediğiniz bu mu?


7
Yalnızca şunu değiştirirdim: function check () {if (! Ws || ws.readyState === WebSocket.CLOSED) start (); }
dieresys

1
Bu yaklaşım ve burada açıklanan canlı tutma tekniği benim için iyi çalışıyor gibi görünüyor.
Peter

@Peter, ws durumunun açık olup olmadığından emin değilim, ping yapmanız gerekir (veya yapmanız gerekir), eğer doğruysam zaten websocket protokolünde. Bu aşırılık sunucunuzda az önce yük oldu ...
comte

@comte bazı ws sunucuları, istemciden mesaj gönderilmediği 'boşta kalma süresinden' sonra bağlantınızı keser ve bu nedenle bağlantıyı açık tutmak için ping kötü bir gerekliliktir.
RozzA

2

Aşağıda projemde kullandığım% 100 çalışan kodlar bulunmaktadır.

  1. Tüm websocket kodunu init işlevinin içine koyun.
  2. Onclose geri aramanın içinde init'i tekrar arayın.
  3. Son olarak, belge hazır işlevi içindeki init işlevini çağırın.

var name = sessionStorage.getItem ('ad');

wsUri =  "ws://localhost:8080";   
var websocket;
$(function() {  
    init();  
    $("#chat_text_box").on("keypress", function(e) {         
        if (e.keyCode == 13) {   //For Enter Button    
            e.preventDefault();
            var mymessage = $('#chat_text_box').val();               
            if(mymessage){
                var msg = {  type: 'chat_text',  data : {  name:name,  msg:mymessage }  };                
                console.log(msg);
                websocket.send(JSON.stringify(msg));
                $('#chat_text_box').val('');
            }               
            return false;                       
        }        
    });      
});     
function init() { 
    websocket = new WebSocket(wsUri);      
    websocket.onopen = function(ev) { /*connection is open */    } 
    websocket.onmessage = function(ev) {        
        var data = JSON.parse(ev.data); //PHP sends Json data        
        var type = data.type;//alert(JSON.stringify(data));
        switch(type) {
            case "chat_text":
                var text = "<div><span class='user'>"+data.data.sender_name+" : </span><span class='msg'>"+data.data.msg+"</span></div>";
                $('#chat-messages').append(text);
                break;            
            default:
                break;

        }        

    };     
    websocket.onerror   = function(ev){}; 
    websocket.onclose = function(ev) {   init();   };  
}

2

Yorum yapamıyorum, ancak şunlar:

var socket;

const socketMessageListener = (event) => {
  console.log(event.data);
};

const socketOpenListener = (event) => {
  console.log('Connected');
  socket.send('hello');
};

const socketCloseListener = (event) => {
  if (socket) {
    console.error('Disconnected.');
  }
  socket = new WebSocket('ws://localhost:8080');
  socket.addEventListener('open', socketOpenListener);
  socket.addEventListener('message', socketMessageListener);
  socket.addEventListener('close', socketCloseListener);
};

socketCloseListener();

// for testing
setTimeout(()=>{
  socket.close();
},5000);

Artı https://www.npmjs.com/package/back zaten yeterince iyi :)


1

function wsConnection(url){
    var ws = new WebSocket(url);
    var s = (l)=>console.log(l);
	ws.onopen = m=>s(" CONNECTED")
    ws.onmessage = m=>s(" RECEIVED: "+JSON.parse(m.data))
    ws.onerror = e=>s(" ERROR")
    ws.onclose = e=>{
        s(" CONNECTION CLOSED");
        setTimeout((function() {
            var ws2 = new WebSocket(ws.url);
			ws2.onopen=ws.onopen;
            ws2.onmessage = ws.onmessage;
            ws2.onclose = ws.onclose;
            ws2.onerror = ws.onerror;
            ws = ws2
        }
        ).bind(this), 5000)
    }
    var f = m=>ws.send(JSON.stringify(m)) || "Sent: "+m;
    f.ping = ()=>ws.send(JSON.stringify("ping"));
    f.close = ()=>ws.close();
    return f
}

c=new wsConnection('wss://echo.websocket.org');
setTimeout(()=>c("Hello world...orld...orld..orld...d"),5000);
setTimeout(()=>c.close(),10000);
setTimeout(()=>c("I am still alive!"),20000);
<pre>
This code will create a websocket which will 
reconnect automatically after 5 seconds from disconnection.

An automatic disconnection is simulated after 10 seconds.


0

Son olarak, aşağıdakine benzer şekilde vue + ts'de ws'yi otomatik olarak yeniden bağlarım:

private async mounted() {
    // Connect to WebSocket
    const sn = "sb1234567890";
    const host =
        window.location.protocol == "https:"
            ? "wss://www.xxx.net"
            : process.env.DEV_TYPE === "fullstack"
            ? "ws://10.0.0.14:8528"
            : "ws://www.xxx.net:8528";
    const wsUri = host + "/feed-home/" + sn;
    await this.startWs(wsUri, sn);
    // !!!Deprecated: failed to reconnect
    // let ws = new WebSocket();
    // console.log(ws);
    // ws.onopen = async function(event) {
    //     console.log(event, "openEvent");
    //     clearInterval(that.timer);
    // };
    // ws.onclose = async function(event) {
    //     console.log(event, "close");
    //     that.timer = setInterval(() => {
    //         console.log("Heart Beat");
    //         ws.send("HeartBeat");
    //         // ws = new WebSocket("ws://10.0.0.14:8528/feed-home/" + sn);
    //         console.log(ws);
    //     }, 60000);
    // };
    // ws.onmessage = async function(event) {
    //     console.log(event, "ws");
    //     alert("get it!");
    //     await alert("please update!");
    //     await that.getHome(sn);
    // };
}
private wsReconnected: boolean = false; // check whether WebSocket is reconnected
private async startWs(uri: string, sn: string) {
    let that = this;
    let ws = new WebSocket(uri);
    ws.onopen = async () => {
        if (that.wsReconnected) {
            await that.getHome(sn); // Refresh api data after reconnected
        }
        ws.send("Current client version: " + window.version);
    };
    ws.onmessage = async evt => {
        await that.getHome(sn);
        that.$message({
            type: "success",
            message: evt.data,
            showClose: true,
            center: true,
            duration: 20 * 1000
        });
    };
    ws.onclose = async () => {
        that.wsReconnected = true;
        await that.startWs(uri, sn);
        const sleep = (seconds: number) => {
            return new Promise(resolve =>
                setTimeout(resolve, seconds * 1000)
            );
        };
        await sleep(10); // Try to reconnect in 10 seconds
        // !!!Deprecated: Use timer will cause multiply ws connections
        // if (!that.wsTimer) {
        //     // Try to reconnect in 10 seconds
        //     that.wsTimer = setInterval(async () => {
        //         console.log("reconnecting websocket...");
        //         await that.startWs(uri, sn);
        //     }, 10 * 1000);
        // }
    };
}

0

WebSocket için istemci tarafı kapatma olayının benim için yararlı olan wasClean özelliği var. İstemci bilgisayarın uyku moduna girmesi vb. Durumlarda veya sunucunun beklenmedik bir şekilde durması vb. Durumlarda true olarak ayarlanmış gibi görünüyor. Soketi manuel olarak kapatırsanız false olarak ayarlanır, bu durumda açmak istemezsiniz soket otomatik olarak tekrar. Angular 7 projesinden alınan kodun altında. Bu kod bir serviste var, bu nedenle herhangi bir bileşenden kullanılabilir.

    notifySocketClose(event) { 

        if (!event.wasClean) { 
            setTimeout(() => {
                this.setupSocket()
            }, 1000);       
        }
    }

    setupSocket() { // my function to handle opening of socket, event binding etc.
    .....
    .....

            this.websocketConnection = this.websocketConnection ? this.websocketConnection : new WebSocket(socketUrl);
            this.websocketConnection.onclose = this.notifySocketClose.bind(this);   
        } 
    }
    .....
    .....

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.