예제 #1
0
 void EmitCloseAndDisconnect()
 {
     if (Socket.State != WebSocketState.Open)
     {
         return;                                      //We can't close a session that is not connected
     }
     //this is ran outside of the send queue as it is already being cancelled
     Task.Run(async() =>
     {
         try
         {
             await WritePacketToSIOSocketAsync(Encoder.Encode(new SocketPacket(EnginePacketType.MESSAGE, SocketPacketType.DISCONNECT, 0, "/", -1, "")), CancellationToken.None);
             //await WritePacketToSIOSocketAsync(Encoder.Encode(new SocketPacket(EnginePacketType.CLOSE)), CancellationToken.None);
             if (Socket.State == WebSocketState.Open)
             {
                 await Socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "normal disconnect", CancellationToken.None);                                      //Usually the server closes the connection but if not... We'll do this cleanly.
             }
         }
         catch (Exception e)
         {
             SocketIOManager.LogWarning("Could not cleanly close Socket.IO connection: " + e.ToString());
         }
         RaiseSIOEvent("close");
     });
 }
예제 #2
0
    public void OffState_ButtonLogin(string szID, string szNickname)
    {
        m_szUserId   = szID;
        m_szNickName = szNickname;

        SocketIOManager.GetManager().Connect();
    }
예제 #3
0
    async Task WritePacketToSIOSocketAsync(string msg, CancellationToken ct)
    {
        if (Socket == null || Socket.State != WebSocketState.Open)
        {
#if UNITY_EDITOR
            //SocketIOManager.LogWarning("You tried to send data over a closed WebSocket. This can sometimes happen when closing the application or stopping \"playMode\" without closing the Socket.IO connection first and is only logged in the editor. You can ignore this warning as it's only a Best-Practice warning");
#endif
            return;
        }

#if VERBOSE
        SocketIOManager.LogDebug("WS > " + msg);
#endif
        var buffer = Encoding.UTF8.GetBytes(msg);
        try
        {
            await Socket.SendAsync(new ArraySegment <byte>(buffer), WebSocketMessageType.Text, true, ct);
        }
        catch (Exception e)
        {
            SIODispatcher.Instance.Enqueue(new Action(() =>
            {
                RaiseSIOEvent("error");
            }));
            lock (Socket)
            {
                if (Status == SIOStatus.CONNECTED)
                {
                    Socket.Abort();
                }
                Status = SIOStatus.ERROR;
            }
            throw e; //pass on
        }
    }
예제 #4
0
    void OnConnect(Socket socket, Packet packet, params object[] args)
    {
        Debug.Log("OnConnect");

        Dictionary <string, object> loginData = new Dictionary <string, object>();

        loginData.Add("userid", m_szUserId);
        loginData.Add("name", m_szNickName);
        SocketIOManager.GetManager().Emit("login", loginData);
    }
예제 #5
0
    internal SocketIONativeInstance(string gameObjectName, string targetAddress, bool enableReconnect) : base(gameObjectName, targetAddress, enableReconnect)
    {
        SocketIOManager.LogDebug("Creating Native Socket.IO instance for " + gameObjectName);

        //Initialize MIT-Licensed helpers
        parser = new Parser();

        sendQueue = new BlockingCollection <Tuple <DateTime, string> >();
        cTokenSrc = new CancellationTokenSource();

        Socket = new ClientWebSocket();
    }
예제 #6
0
    // Start is called before the first frame update
    void Start()
    {
        GameObject SIOMObj = GameObject.Find("SocketIOManager");

        socketIOManager = SIOMObj.GetComponent <SocketIOManager>();

        if (!PlayerNetwork.Instance.isGuest)
        {
            socketIOManager.playerStats(PlayerNetwork.Instance.PlayerName);
        }

        PlayerNameText.text = PlayerNetwork.Instance.PlayerName;
    }
예제 #7
0
    // Use this for initialization
    void Start()
    {
        SocketIOManager.GetManager().Create(m_ConnectUrl + "/socket.io/");
        SocketIOManager.GetManager().On(SocketIOEventTypes.Connect, OnConnect);

        SocketIOManager.GetManager().On("login", OnLogin);
        SocketIOManager.GetManager().On("lobby", OnLobby);
        SocketIOManager.GetManager().On("garage", OnGarage);
        SocketIOManager.GetManager().On("room", OnRoom);
        SocketIOManager.GetManager().On("gamestart", OnGameStart);
        SocketIOManager.GetManager().On("gameend", OnGameEnd);

        m_fsm.ChangeState(ScenarioStates.OffState);
    }
예제 #8
0
    internal SocketIONativeInstance(string instanceName, string targetAddress) : base(instanceName, targetAddress)
    {
        SocketIOManager.LogDebug("Creating Native Socket.IO instance for " + instanceName);
        this.InstanceName  = instanceName;
        this.targetAddress = "ws" + targetAddress.Substring(4);

        //Initialize MIT-Licensed helpers
        parser = new Parser();

        sendQueue = new BlockingCollection <Tuple <DateTime, string> >();
        cTokenSrc = new CancellationTokenSource();

        Socket = new ClientWebSocket();
    }
예제 #9
0
    public void OnClick_SignOut()
    {
        PhotonNetwork.Disconnect();

        GameObject      SIOMObj = GameObject.Find("SocketIOManager");
        SocketIOManager SIOM    = SIOMObj.GetComponent <SocketIOManager>();

        SIOM.SignOutFromMenu();
        //  PlayerNetwork.Instance.firebaseAuth.SignOut();

        DDOL = GameObject.Find("DDOL");
        Destroy(DDOL);

        SceneManager.LoadScene(0);
    }
예제 #10
0
    void OnLogin(Socket socket, Packet packet, params object[] args)
    {
        Dictionary <string, object> data = args[0] as Dictionary <string, object>;

        Debug.Log("OnLogin : "******"score : " + data["score"].ToString());
        Debug.Log("result : " + data["result"].ToString());

        m_iScore = (int)(double)data["score"];
        int iResult = (int)(double)data["result"];

        if (iResult == 1)
        {
            // send lobby
            SocketIOManager.GetManager().Emit("lobby");
        }
        else
        {
            Debug.Log("error");
        }
    }
예제 #11
0
 //Receiver for JSLib-Events
 private void SIOErrorRelay(string logMsg)
 {
     SocketIOManager.LogError(logMsg);
 }
예제 #12
0
    /// <summary>
    /// Lobby
    /// </summary>
    ///

    public void ResultState_Button()
    {
        SocketIOManager.GetManager().Emit("lobby");
    }
예제 #13
0
 public void GameState_ButtonBack()
 {
     SocketIOManager.GetManager().Emit("lobby");
 }
예제 #14
0
    /// <summary>
    /// Lobby
    /// </summary>
    ///

    public void GameState_ButtonGameEnd()
    {
        SocketIOManager.GetManager().Emit("gameend");
    }
예제 #15
0
    /// <summary>
    /// Lobby
    /// </summary>
    ///

    public void RoomState_ButtonGameStart()
    {
        SocketIOManager.GetManager().Emit("gamestart");
    }
예제 #16
0
 public void LobbyState_ButtonRoom()
 {
     SocketIOManager.GetManager().Emit("room");
 }
예제 #17
0
 public void LobbyState_ButtonGarage()
 {
     SocketIOManager.GetManager().Emit("garage");
 }
예제 #18
0
    private async void SIOSocketReader()
    {
        while (!cTokenSrc.IsCancellationRequested)
        {
            var message = "";
            var binary  = new List <byte>();

READ:
            var buffer = new byte[1024];
            WebSocketReceiveResult res = null;

            try
            {
                res = await Socket.ReceiveAsync(new ArraySegment <byte>(buffer), cTokenSrc.Token);

                if (cTokenSrc.IsCancellationRequested)
                {
                    return;
                }
            }
            catch
            {
                //Something went wrong
                if (cTokenSrc.IsCancellationRequested)
                {
                    return;
                }
                Status = SIOStatus.ERROR;
                SIODispatcher.Instance.Enqueue(new Action(() => { RaiseSIOEvent("disconnect", "server namespace disconnect"); }));
                Socket.Abort();
                break;
            }

            if (res == null)
            {
                goto READ; //we got nothing. Wait for data.
            }
            if (res.MessageType == WebSocketMessageType.Close)
            {
                cTokenSrc.Cancel();
                Status = SIOStatus.DISCONNECTED;
                SIODispatcher.Instance.Enqueue(new Action(() => { RaiseSIOEvent("disconnect", "server namespace disconnect"); }));
                return;
            }
            else if (res.MessageType == WebSocketMessageType.Text)
            {
                if (!res.EndOfMessage)
                {
                    message += Encoding.UTF8.GetString(buffer).TrimEnd('\0');
                    goto READ;
                }
                message += Encoding.UTF8.GetString(buffer).TrimEnd('\0');

                SocketPacket packet = Decoder.Decode(message);

                switch (packet.enginePacketType)
                {
                case EnginePacketType.OPEN:
                    SocketID = JsonUtility.FromJson <SocketOpenData>(packet.json).sid;

                    SIODispatcher.Instance.Enqueue(new Action(() =>
                    {
                        RaiseSIOEvent("open");
                    }));
                    break;

                case EnginePacketType.CLOSE:
                    SIODispatcher.Instance.Enqueue(new Action(() =>
                    {
                        RaiseSIOEvent("close");
                    }));
                    break;

                case EnginePacketType.MESSAGE:
                    if (packet.json == "")
                    {
                        buffer  = null;
                        message = "";
                        continue;
                    }

                    if (packet.socketPacketType == SocketPacketType.ACK)
                    {
                        SocketIOManager.LogWarning("ACK is not supported by this library.");
                    }

                    if (packet.socketPacketType == SocketPacketType.EVENT)
                    {
                        SIOEventStructure e = Parser.Parse(packet.json);
                        SIODispatcher.Instance.Enqueue(new Action(() =>
                        {
                            RaiseSIOEvent(e.eventName, e.data);
                        }));
                    }
                    break;

                case EnginePacketType.PING:
                    EmitPacket(new SocketPacket(EnginePacketType.PONG));
                    break;

                case EnginePacketType.PONG:
                    waitingForPong = false;     //woohoo!
                    break;

                default:
                    SocketIOManager.LogWarning("Unhandled SIO packet: " + message);
                    break;
                }
            }
            else
            {
                if (!res.EndOfMessage)
                {
                    goto READ;
                }
                SocketIOManager.LogWarning("Received binary message");
            }
            buffer = null;
        }
    }
    private void Start()
    {
        GameObject SIOMObj = GameObject.Find("SocketIOManager");

        socketIOManager = SIOMObj.GetComponent <SocketIOManager>();
    }
예제 #20
0
    private async void SIOSocketReader()
    {
        bool haveIEverBeenConnected = false;

        while (!cTokenSrc.Token.IsCancellationRequested)
        {
            var message = "";
            var binary  = new List <byte>();

READ:
            var buffer = new byte[1024];
            WebSocketReceiveResult res = null;

            try
            {
                res = await Socket.ReceiveAsync(new ArraySegment <byte>(buffer), cTokenSrc.Token);

                if (cTokenSrc.Token.IsCancellationRequested)
                {
                    return;
                }
            }
            catch
            {
                if (Status != SIOStatus.CONNECTED)
                {
                    return;                                //Yeah, we already know. Wait for reconnect
                }
                //Something went wrong
                if (cTokenSrc.Token.IsCancellationRequested)
                {
                    return;
                }
                if (Status == SIOStatus.CONNECTED)
                {
                    Socket.Abort();
                }
                Status = SIOStatus.ERROR;
                SIODispatcher.Instance.Enqueue(new Action(() => { RaiseSIOEvent((haveIEverBeenConnected ? "disconnect" : (ReconnectAttempts > 0 ? "reconnect_error" : "connect_error")), (Socket.State == WebSocketState.CloseReceived || Socket.State == WebSocketState.Closed ? "transport close" : "transport error")); }));
                return;
            }

            if (res == null)
            {
                goto READ; //we got nothing. Wait for data.
            }
            if (res.MessageType == WebSocketMessageType.Close)
            {
                if (cTokenSrc.Token.IsCancellationRequested || Status != SIOStatus.CONNECTED)
                {
                    return;
                }
                Status = SIOStatus.ERROR;
                SIODispatcher.Instance.Enqueue(new Action(() => { RaiseSIOEvent((haveIEverBeenConnected ? "disconnect" : (ReconnectAttempts > 0 ? "reconnect_error" : "connect_error")), "transport close"); }));
                return;
            }
            else if (res.MessageType == WebSocketMessageType.Text)
            {
                if (!res.EndOfMessage)
                {
                    message += Encoding.UTF8.GetString(buffer).TrimEnd('\0');
                    goto READ;
                }
                message += Encoding.UTF8.GetString(buffer).TrimEnd('\0');

#if VERBOSE
                SocketIOManager.LogDebug("WS < " + message);
#endif

                SocketPacket packet = Decoder.Decode(message);

                switch (packet.enginePacketType)
                {
                case EnginePacketType.OPEN:
                    SocketOpenData sockData = JsonUtility.FromJson <SocketOpenData>(packet.json);
                    SocketID     = null;
                    pingInterval = sockData.pingInterval;
                    pingTimeout  = sockData.pingTimeout;

                    //Serialize Payload
                    string payload = "";
                    if (authPayload != null)
                    {
                        payload = authPayload.GetPayloadJSON();
                    }

                    //Hey Server, how are you today?
                    EmitPacket(new SocketPacket(EnginePacketType.MESSAGE, SocketPacketType.CONNECT, 0, "/", -1, payload));

                    SIODispatcher.Instance.Enqueue(new Action(() =>
                    {
                        RaiseSIOEvent("open");
                    }));
                    break;

                case EnginePacketType.CLOSE:
                    SIODispatcher.Instance.Enqueue(new Action(() =>
                    {
                        RaiseSIOEvent("close");
                    }));
                    break;

                case EnginePacketType.MESSAGE:
                    if (packet.socketPacketType == SocketPacketType.EVENT && packet.json == "")
                    {
                        buffer  = null;
                        message = "";
                        continue;
                    }

                    if (packet.socketPacketType == SocketPacketType.CONNECT)
                    {
                        //Extract socket id
                        string tmpExtractionSubstr = packet.json.Substring(packet.json.IndexOf("sid\":") + 4).Trim();
                        tmpExtractionSubstr = tmpExtractionSubstr.Substring(tmpExtractionSubstr.IndexOf("\"") + 1, tmpExtractionSubstr.IndexOf("}") - 1);
                        SocketID            = tmpExtractionSubstr.Substring(0, tmpExtractionSubstr.IndexOf("\""));

                        //invoke "connect" event
                        Status = SIOStatus.CONNECTED;
                        if (ReconnectAttempts > 0)
                        {
                            SIODispatcher.Instance.Enqueue(new Action(() => { RaiseSIOEvent("reconnect", null); }));
                        }
                        SIODispatcher.Instance.Enqueue(new Action(() => { RaiseSIOEvent("connect", null); }));
                        haveIEverBeenConnected = true;
                        ReconnectAttempts      = 0;
                    }
                    else if (packet.socketPacketType == SocketPacketType.DISCONNECT)
                    {
                        SIODispatcher.Instance.Enqueue(new Action(() => { RaiseSIOEvent("disconnect", "io server disconnect"); }));
                        FinishOperation();
                    }
                    else if (packet.socketPacketType == SocketPacketType.ACK)
                    {
                        SocketIOManager.LogWarning("ACK is not supported by this library.");
                    }
                    else if (packet.socketPacketType == SocketPacketType.EVENT)
                    {
                        SIOEventStructure e = Parser.Parse(packet.json);
                        SIODispatcher.Instance.Enqueue(new Action(() =>
                        {
                            RaiseSIOEvent(e.eventName, e.data);
                        }));
                    }
                    break;

                case EnginePacketType.PING:
                    lastPing = DateTime.Now;
                    EmitPacket(new SocketPacket(EnginePacketType.PONG));
                    break;

                default:
                    SocketIOManager.LogWarning("Unhandled SIO packet: " + message);
                    break;
                }
            }
            else
            {
                if (!res.EndOfMessage)
                {
                    goto READ;
                }
                SocketIOManager.LogWarning("Received binary message");
            }
            buffer = null;
        }
    }
예제 #21
0
 // Use this for initialization
 void Start()
 {
     socketIOManager = GameObject.Find("SocketIOCanvas").GetComponent <SocketIOManager>();
 }
예제 #22
0
    public override void Connect(string targetAddress, bool enableReconnect, SIOAuthPayload authPayload)
    {
        base.Connect(targetAddress, enableReconnect, authPayload);

        Task.Run(async() =>
        {
            //We need a fresh (uncancelled) source
            cTokenSrc = new CancellationTokenSource();

            if (ReconnectAttempts > 0)
            {
                SIODispatcher.Instance.Enqueue(new Action(() => { RaiseSIOEvent("reconnect_attempt", ReconnectAttempts.ToString()); }));
            }

            //Kill all remaining threads
            if (Socket != null && Socket.State == WebSocketState.Open)
            {
                await Socket.CloseAsync(WebSocketCloseStatus.ProtocolError, "Reconnect required", cTokenSrc.Token);
            }
            //else if (ReconnectAttempts > 0) SIODispatcher.Instance.Enqueue(new Action(() => { RaiseSIOEvent("reconnect_attempt", ReconnectAttempts.ToString()); }));

            lock (Socket)
            {
                Socket = new ClientWebSocket();
            }

            try
            {
                string websocketAddress = "ws" + targetAddress.Substring(4);
                if (targetAddress.IndexOf("/", 8) == -1)
                {
                    websocketAddress += "/socket.io/";
                }
                Uri baseUri = new Uri(websocketAddress);

                SocketIOManager.LogDebug("Connecting to server " + baseUri.Scheme + "://" + baseUri.Host + ":" + baseUri.Port + " on path " + baseUri.AbsolutePath);
                Uri connectTarget = new Uri(baseUri.Scheme + "://" + baseUri.Host + ":" + baseUri.Port + baseUri.AbsolutePath + "?EIO=4&transport=websocket" + (baseUri.Query.Length > 1 ? "&" + baseUri.Query.Substring(1) : ""));
                await Socket.ConnectAsync(connectTarget, CancellationToken.None);
                for (int i = 0; i < 50 && Socket.State != WebSocketState.Open; i++)
                {
                    Thread.Sleep(50);
                }
                if (Socket.State != WebSocketState.Open)
                {
                    //Something went wrong. This should not happen. Stop operation, wait a moment and try again
                    cTokenSrc.Cancel();
                    Thread.Sleep(1500);
                    Connect();
                }
            }
            catch (Exception e)
            {
                if (ReconnectAttempts == 0)
                {
                    SocketIOManager.LogError(InstanceName + ": " + e.GetType().Name + " - " + e.Message + " (" + targetAddress + ")");
                    if (e.GetType().Equals(typeof(WebSocketException)))
                    {
                        SocketIOManager.LogWarning(InstanceName + ": Please make sure that your server supports the 'websocket' transport. Load-Balancers, Reverse Proxies and similar appliances often require special configuration.");
                    }
                    if (e.GetType().Equals(typeof(System.Security.Authentication.AuthenticationException)))
                    {
                        SocketIOManager.LogWarning(InstanceName + ": Please verify that your server is using a valid SSL certificate which is trusted by this client's system CA store");
                    }
                    SIODispatcher.Instance.Enqueue(new Action(() => { RaiseSIOEvent("connect_error", e.GetType().Name + " - " + e.Message); }));
                    //SIODispatcher.Instance?.Enqueue(new Action(() => { RaiseSIOEvent("connect_timeout", null); }));
                }
                else
                {
                    SocketIOManager.LogError(InstanceName + ": " + e.GetType().Name + " - " + e.Message + " (while reconnecting) ");
                    SIODispatcher.Instance.Enqueue(new Action(() => { RaiseSIOEvent("reconnect_error", e.GetType().Name + " - " + e.Message); }));
                }
                Status = SIOStatus.ERROR;

                //Limit the max reconnect attemts
                if (ReconnectAttempts > 150)
                {
                    Status = SIOStatus.ERROR;
                    SIODispatcher.Instance?.Enqueue(new Action(() => { RaiseSIOEvent("reconnect_failed"); }));
                    return;
                }

                //An error occured while connecting, we need to reconnect.
                Thread.Sleep(500 + (ReconnectAttempts++ *1000));
                if (!cTokenSrc.IsCancellationRequested)
                {
                    Connect(authPayload);
                }
                return;
            }

            try
            {
                if (WebSocketReaderThread == null || !WebSocketReaderThread.IsAlive)
                {
                    WebSocketReaderThread = new Thread(new ThreadStart(SIOSocketReader));
                    WebSocketReaderThread.Start();
                }

                if (WebSocketWriterThread == null || !WebSocketWriterThread.IsAlive)
                {
                    WebSocketWriterThread = new Thread(new ThreadStart(SIOSocketWriter));
                    WebSocketWriterThread.Start();
                }

                if (WatchdogThread == null || !WatchdogThread.IsAlive)
                {
                    WatchdogThread = new Thread(new ThreadStart(SIOSocketWatchdog));
                    WatchdogThread.Start();
                }
            }
            catch (Exception e)
            {
                SocketIOManager.LogError("Exception while starting threads on " + InstanceName + ": " + e.ToString());
                Status = SIOStatus.ERROR;
                return;
            }
        });
    }
예제 #23
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();
    }
예제 #24
0
 //Receiver for JSLib-Events
 private void SIOWarningRelay(string logMsg)
 {
     SocketIOManager.LogWarning(logMsg);
 }
예제 #25
0
    /// <summary>
    /// Lobby
    /// </summary>
    ///

    public void LobbyState_ButtonLobby()
    {
        SocketIOManager.GetManager().Emit("lobby");
    }
예제 #26
0
 void Awake()
 {
     _instance = this;
 }
예제 #27
0
    public override void Connect()
    {
        Task.Run(async() =>
        {
            //Kill all remaining threads
            if (Socket != null && Socket.State == WebSocketState.Open)
            {
                await Socket.CloseAsync(WebSocketCloseStatus.ProtocolError, "Reconnect required", cTokenSrc.Token);
            }
            else if (ReconnectAttempts > 0)
            {
                SIODispatcher.Instance.Enqueue(new Action(() => { RaiseSIOEvent("reconnecting", ReconnectAttempts.ToString()); }));
            }

            lock (Socket)
            {
                Socket = new ClientWebSocket();
            }

            try
            {
                Uri baseUri       = new Uri(targetAddress);
                Uri connectTarget = new Uri(baseUri.Scheme + "://" + baseUri.Host + ":" + baseUri.Port + "/socket.io/?EIO=4&transport=websocket" + (baseUri.Query.Length > 1 ? "&" + baseUri.Query.Substring(1) : ""));
                await Socket.ConnectAsync(connectTarget, cTokenSrc.Token);
                for (int i = 0; i < 50 && Socket.State != WebSocketState.Open; i++)
                {
                    Thread.Sleep(25);
                }
                if (Socket.State != WebSocketState.Open)
                {
                    return;                                      //let the watchdog try it again
                }
            }
            catch (Exception e)
            {
                if (ReconnectAttempts == 0)
                {
                    SocketIOManager.LogError(InstanceName + ": " + e.Message);
                    SIODispatcher.Instance.Enqueue(new Action(() => { RaiseSIOEvent("connect_error", e.Message); }));
                }
                else
                {
                    SocketIOManager.LogError(InstanceName + ": " + e.Message + " (while reconnecting) ");
                    SIODispatcher.Instance.Enqueue(new Action(() => { RaiseSIOEvent("reconnect_error", e.Message); }));
                }
                Status = SIOStatus.ERROR;
                return;
            }

            try
            {
                if (WebSocketReaderThread == null || !WebSocketReaderThread.IsAlive)
                {
                    WebSocketReaderThread = new Thread(new ThreadStart(SIOSocketReader));
                    WebSocketReaderThread.Start();
                }

                if (WebSocketWriterThread == null || !WebSocketWriterThread.IsAlive)
                {
                    WebSocketWriterThread = new Thread(new ThreadStart(SIOSocketWriter));
                    WebSocketWriterThread.Start();
                }

                if (WatchdogThread == null || !WatchdogThread.IsAlive)
                {
                    WatchdogThread = new Thread(new ThreadStart(SIOSocketWatchdog));
                    WatchdogThread.Start();
                }
            }
            catch (Exception e)
            {
                SocketIOManager.LogError("Exception while starting threads on " + InstanceName + ": " + e.ToString());
                Status = SIOStatus.ERROR;
            }

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

        base.Connect();
    }