private void SIOSocketWatchdog()
    {
        //We wait a moment and then start with current time as the first ping will last up to pingInterval
        Thread.Sleep(1000);
        lastPing = DateTime.Now;
        System.Random rng = new System.Random();

        while (!cTokenSrc.IsCancellationRequested)
        {
            Thread.Sleep(500);

            if (Status == SIOStatus.RECONNECTING)
            {
                continue;                                   //Wait for running attempt to end
            }
            if (DateTime.Now.Subtract(lastPing).TotalSeconds > (pingInterval + pingTimeout) || Socket.State != WebSocketState.Open)
            {
                if (cTokenSrc.IsCancellationRequested)
                {
                    return;
                }

                //Send events for some constellations
                if (Socket.State == WebSocketState.Open)
                {
                    SIODispatcher.Instance?.Enqueue(new Action(() => { RaiseSIOEvent("disconnect", "ping timeout"); }));
                }
                else if (Status == SIOStatus.CONNECTED)
                {
                    SIODispatcher.Instance?.Enqueue(new Action(() => { RaiseSIOEvent("disconnect", "transport close"); }));
                }

                //Set the status flag
                if (enableAutoReconnect)
                {
                    Status = SIOStatus.RECONNECTING;
                }
                else
                {
                    Status = SIOStatus.DISCONNECTED;
                }

                //We need to stop the handler threads before reconnecting else we might see double reconnects as of exceptions raised in them
                if (WebSocketReaderThread != null && WebSocketReaderThread.IsAlive)
                {
                    WebSocketReaderThread.Abort();
                }
                if (WebSocketWriterThread != null && WebSocketWriterThread.IsAlive)
                {
                    WebSocketWriterThread.Abort();
                }

                if (enableAutoReconnect)
                {
                    Thread.Sleep(300 + (ReconnectAttempts++ *1500) + rng.Next(50, 1000));  //Wait a moment in favor of the event handler and add some delay and jitter, not to hammer the server

                    if (cTokenSrc.IsCancellationRequested)
                    {
                        return;
                    }
                    Connect(); //reconnect
                }
                return;        //End the watchdog. It will be restarted after successful connect
            }
        }
    }
Exemple #2
0
    public override void Connect()
    {
        Task.Run(async() =>
        {
            //Kill all remaining threads
            if (WebSocketReaderThread != null && WebSocketReaderThread.IsAlive)
            {
                WebSocketReaderThread.Abort();
            }
            if (WebSocketWriterThread != null && WebSocketWriterThread.IsAlive)
            {
                WebSocketWriterThread.Abort();
            }
            if (PingPongThread != null && PingPongThread.IsAlive)
            {
                PingPongThread.Abort();
            }

            lock (Socket)
            {
                Socket = new ClientWebSocket();
            }
            try
            {
                Uri baseUri       = new Uri(targetAddress);
                Uri connectTarget = new Uri(baseUri.Scheme + "://" + baseUri.Host + ":" + baseUri.Port + "/socket.io/?EIO=3&transport=websocket" + (baseUri.Query.Length > 1 ? "&" + baseUri.Query.Substring(1) : ""));
                await Socket.ConnectAsync(connectTarget, cTokenSrc.Token);
                while (Socket.State != WebSocketState.Open)
                {
                    Thread.Sleep(25);
                }
                ;
            }
            catch (Exception e)
            {
                //TODO Timeout?
                SocketIOManager.LogError(InstanceName + ": " + e.Message);
                SIODispatcher.Instance.Enqueue(new Action(() => { RaiseSIOEvent("connect_error", e.Message); }));
                Status = SIOStatus.ERROR;
                return;
            }

            try
            {
                WebSocketReaderThread = new Thread(new ThreadStart(SIOSocketReader));
                WebSocketWriterThread = new Thread(new ThreadStart(SIOSocketWriter));
                PingPongThread        = new Thread(new ThreadStart(SIOSocketWatchdog));

                WebSocketReaderThread.Start();
                WebSocketWriterThread.Start();
                PingPongThread.Start();
            }
            catch (Exception e)
            {
                SocketIOManager.LogError("Exception while starting threads on " + InstanceName + ": " + e.ToString());
            }
            //Thread.Sleep(100);

            Status = SIOStatus.CONNECTED;

            SIODispatcher.Instance.Enqueue(new Action(() => { RaiseSIOEvent("connect", null); }));
        });

        base.Connect();
    }