WebSocket में सर्वर रिबूट होने पर क्लाइंट का पुन: कनेक्शन


93

मैं क्लाइंट के रूप में PHP5 और क्रोम ब्राउज़र का उपयोग करके वेब सॉकेट का उपयोग कर रहा हूं। मैंने साइट http://code.google.com/p/phpwebsocket/ से कोड ले लिया है ।

मैं सर्वर चलाता हूं, और क्लाइंट भी जुड़ा हुआ है। मैं चैट भी कर सकता हूं। अब जब मैं सर्वर को पुनरारंभ करता हूं (इसे मारकर और इसे फिर से शुरू करके), क्लाइंट को डिस्कनेक्ट की गई जानकारी मिलती है, लेकिन जब मैं संदेश भेजता हूं तो स्वचालित रूप से सर्वर के साथ फिर से कनेक्ट नहीं होता है।

इसे कैसे प्राप्त किया जाए? जैसे जब मुझे डिस-कनेक्टेड जानकारी मिलती है, तो क्या मुझे इसकी जांच करनी चाहिए और पेज को रिफ्रेश करने या फिर से जोड़ने के लिए इसे जावास्क्रिप्ट पर भेजना चाहिए?

जवाबों:


143

जब सर्वर रिबूट होता है, तो वेब सॉकेट कनेक्शन बंद हो जाता है, इसलिए जावास्क्रिप्ट oncloseइवेंट ट्रिगर होता है। यहां एक उदाहरण दिया गया है जो हर पांच सेकंड में पुन: कनेक्ट करने का प्रयास करता है।

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
मुझे आशा है कि एक नई वस्तु का निर्माण किए बिना और कार्यक्रम के कार्यों को परिभाषित करने के बिना, अधिक सुरुचिपूर्ण तरीका है ...
ciembor

3
5 मिनट के बाद, ब्राउज़र जमा देता है। क्या केवल मैं ही हूं?
मार्क

16
आपको "ws = null; जोड़ना चाहिए;" सेट टाइमआउट () से पहले गुणा ws ऑब्जेक्ट्स और इवेंटहैंडलिग्स से बचने के लिए
मैक्स

8
अगर मैं गलत हूं तो मुझे सुधारें, लेकिन यह कोड एक तरह का खतरनाक है क्योंकि एक निश्चित मात्रा में डिस्कनेक्ट से स्टैक ओवरफ्लो होगा। ऐसा इसलिए है क्योंकि आप startपुनरावर्ती कॉल करते हैं , बिना कभी लौटते हुए।
१४:१६

10
@Forivin कोई स्टैकओवरफ़्लो समस्या यहाँ नहीं है। चूँकि जावास्क्रिप्ट में केवल 1 सिंगल थ्रेड है, जो किसी भी समय हमारे कोड को निष्पादित करता है, सेट टाइमआउट () उस सिंगल थ्रेड के फिर से मुक्त होने पर भविष्य में निष्पादित होने वाले फ़ंक्शन को शेड्यूल करता है। सेटटाइमआउट () के बाद यहां बुलाया जाता है, थ्रेड फ़ंक्शन से वापस आ जाता है (स्टैक को साफ करता है), फिर कतार में अगले कार्यक्रम को संसाधित करने के लिए जाता है। यह अंततः हमारे अनाम फ़ंक्शन को मिलेगा जो कॉल शुरू करते हैं और इसे स्टैक में शीर्ष फ्रेम के रूप में कहा जाएगा।
बदबूदार

39

एंड्रयू द्वारा दिया गया समाधान पूरी तरह से काम नहीं कर रहा है, क्योंकि खोए कनेक्शन के मामले में, सर्वर कई करीबी घटनाओं को भेज सकता है।

उस स्थिति में, आप कई सेटटिमाउट सेट करेंगे। एंड्रयू द्वारा दिया गया समाधान केवल तभी काम कर सकता है जब सर्वर पांच सेकंड से पहले तैयार हो।

फिर, एंड्रयू समाधान के आधार पर, फिर से काम किया, मैंने विंडो ऑब्जेक्ट के लिए ID संलग्न करने में setInterval का उपयोग किया है (इस तरह यह "हर जगह उपलब्ध है"):

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यदि आप उन्हें "ग्लोबल टाइमर आईडी" विचार लागू करते हैं;)
रोज़ा

3
"एंड्रयू द्वारा दिया गया समाधान केवल तभी काम कर सकता है जब सर्वर पाँच सेकंड से पहले तैयार हो जाए।" - कथन सत्य नहीं है। यदि सर्वर पांच सेकंड के बाद भी अनुपलब्ध है, तो आपका क्लाइंट WebSocket कनेक्शन खोलने में विफल रहेगा और oncloseघटना फिर से निकाल दी जाएगी।
सौरव घोष

36

ReconnectingWebSocket

GitHub एक छोटा सा JavaScript लाइब्रेरी होस्ट करता है, जो WebSocket कनेक्शन प्रदान करने के लिए WebSocket API को सजाता है, जो कनेक्शन ड्रॉप होने पर स्वचालित रूप से फिर से कनेक्ट हो जाएगा।

गज़िप संपीड़न के साथ न्यूनतम पुस्तकालय 600 बाइट्स से कम है।

आधिकारिक भंडार यहां उपलब्ध है:

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

सर्वर बाढ़

यदि रिबूट होने पर सर्वर से अधिक संख्या में क्लाइंट जुड़े होते हैं। एक्सपोनेंशियल बैकऑफ़ एल्गोरिथ्म का उपयोग करके क्लाइंट के पुन: कनेक्ट किए गए समय को प्रबंधित करना सार्थक हो सकता है।

एल्गोरिथ्म इस तरह काम करता है:

  1. K प्रयासों के लिए, 0 और 2 ^ k - 1 के बीच समय का एक यादृच्छिक अंतराल उत्पन्न करें,
  2. यदि आप पुन: कनेक्ट करने में सक्षम हैं, तो k को 1 पर रीसेट करें:
  3. यदि पुन: संयोजन विफल हो जाता है, k 1 से बढ़ता है और चरण 1 पर प्रक्रिया फिर से शुरू होती है,
  4. अधिकतम अंतराल को कम करने के लिए, जब कश्मीर की एक निश्चित संख्या तक पहुँच गया है, तो प्रत्येक प्रयास के बाद k बढ़ना बंद हो जाता है।

संदर्भ:

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

ReconnectingWebSocket इस एल्गोरिथ्म का उपयोग करके पुन: कनेक्ट नहीं करता है।


महान जवाब, विशेष रूप से क्योंकि यह एक उच्च सर्वर लोड के जोखिम का उल्लेख करता है जब सर्वर वेब सॉकेट कनेक्शन बंद कर देता है, और सभी क्लाइंट (जो सैकड़ों या हजारों हो सकते हैं) एक ही समय में पुन: कनेक्ट करने का प्रयास करते हैं। घातीय बैकऑफ़ के बजाय, आप 0 और 10 सेकंड के बीच की देरी को भी यादृच्छिक कर सकते हैं। जो सर्वर पर लोड को भी फैलाएगा।
जोकेम शुल्नेक्लोपर

30

मैं कुछ समय के लिए शुद्ध वेनिला जावास्क्रिप्ट के लिए इस पैटन का उपयोग कर रहा हूं, और यह अन्य उत्तरों की तुलना में कुछ अधिक मामलों का समर्थन करता है।

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


});

जैसे ही सर्वर कनेक्शन को बंद करेगा, यह पुनः प्रयास करेगा, और यह सुनिश्चित करने के लिए कनेक्शन की जाँच करेगा कि यह हर 5 सेकंड में है।

इसलिए यदि सर्वर चालू नहीं होता है, तो यह चलता है या ऑनक्लोज़ इवेंट के समय कनेक्शन तब भी वापस आ जाएगा, जब यह ऑनलाइन वापस आ जाएगा।

नोट: इस स्क्रिप्ट का उपयोग करने से आप कभी भी कनेक्शन खोलने की कोशिश करना बंद नहीं कर पाएंगे ... लेकिन मुझे लगता है कि आप क्या चाहते हैं?


7
मैं केवल परिवर्तन करूंगा: फ़ंक्शन चेक () {if (ws || ws.readyState === WebSocket.CLOSED) प्रारंभ (); }
डेरीसिस

1
यह दृष्टिकोण, साथ ही यहाँ वर्णित एक जीवित तकनीक , मेरे लिए अच्छी तरह से काम करता है।
पीटर

@Peter, सुनिश्चित नहीं है कि अगर ws स्टेट ओपन है तो आपको पिंग करने की जरूरत है (या चाहिए), अगर मैं सही हूं तो यह पहले से ही वेबस्कॉक प्रोटोकॉल में है। यह ओवरकिल आपके सर्वर पर बस लोड था ...
comte

@comte कुछ ws सर्वर क्लाइंट से भेजे जा रहे संदेशों की 'निष्क्रिय अवधि' के बाद आपको डिस्कनेक्ट कर देते हैं और कनेक्शन को खुला रखने के लिए पिंग एक बुरी आवश्यकता है।
रोजा

2

नीचे मेरी परियोजना में उपयोग किए गए कोड हैं जो 100% काम कर रहे हैं।

  1. Init फंक्शन के अंदर सभी websocket कोड डालें।
  2. Onclose कॉलबैक के अंदर फिर से init कॉल करें।
  3. अंत में दस्तावेज़ तैयार फ़ंक्शन के अंदर इनिट फ़ंक्शन को कॉल करें।

var name = sessionStorage.getItem ('नाम');

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

टिप्पणी नहीं कर सकते, लेकिन निम्नलिखित:

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

प्लस https://www.npmjs.com/package/back पहले से ही काफी अच्छा है :)


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

अंत में, मैं vs + ts में ws ऑटो को फिर से कनेक्ट करता हूं, जैसा कि निम्नलिखित है:

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 के लिए क्लाइंट साइड क्लोज इवेंट में एक .Clean प्रॉपर्टी है, जो मेरे लिए उपयोगी थी। ऐसा लगता है कि यह उन मामलों में सही है जहां क्लाइंट कंप्यूटर स्लीप मोड में चला जाता है आदि या जब सर्वर अप्रत्याशित रूप से बंद हो जाता है आदि। यह गलत पर सेट होता है यदि आप मैन्युअल रूप से सॉकेट बंद करते हैं, तो उस स्थिति में जिसे आप खोलना नहीं चाहते हैं। सॉकेट स्वचालित रूप से फिर से। एक कोणीय 7 परियोजना से नीचे कोड। मेरे पास एक सेवा में यह कोड है, इसलिए यह किसी भी घटक से उपयोग करने योग्य है।

    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);   
        } 
    }
    .....
    .....
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.