/// <summary> /// Connect this Socket.IO instance to a new target (this even works after the initial connect) /// </summary> /// <param name="targetAddress">The server / IO address to connect to. Has to start with http:// or https:// (substitute ws with http or wss with https): http[s]://<Hostname>[:<Port>][/<path>]</param> /// <param name="enableReconnect">Shall we reconnect automatically on an unexpected connection loss?</param> /// <param name="authPayload">Null or an instance of SIOAuthPayload to be sent upon connection. Can for example be used to send an authentication token.</param> public virtual void Connect(string targetAddress, bool enableReconnect, SIOAuthPayload authPayload) { if (!targetAddress.StartsWith("http://") && !targetAddress.StartsWith("https://")) { throw new UriFormatException("Socket.IO Address has to start with http:// or https:// if provided programmatically"); } this.targetAddress = targetAddress; this.enableAutoReconnect = enableReconnect; this.authPayload = authPayload; }
public override void Connect(string targetAddress, bool enableReconnect, SIOAuthPayload authPayload) { base.Connect(targetAddress, enableReconnect, authPayload); string payload = ""; if (this.authPayload != null) { payload = this.authPayload.GetPayloadJSON(); } SocketIOManager.LogDebug("Creating and connecting WebGL-Based Socket.IO instance for " + this.GameObjectName); CreateSIOInstance(InstanceName, this.GameObjectName, targetAddress, enableReconnect ? 1 : 0, payload); }
/// <summary> /// Connect this Socket.IO instance using the component's set configuration but with (new) auth data /// </summary> /// <param name="authPayload">An instance of SIOAuthPayload to be sent upon (re-)connection. Can for example be used to send an authentication token.</param> public virtual void Connect(SIOAuthPayload authPayload) { Connect(targetAddress, this.enableAutoReconnect, authPayload); }
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; } }); }
// Start is called before the first frame update void Start() { //sioCom is assigned via inspector so no need to initialize it. //We just fetch the actual Socket.IO instance using its integrated Instance handle and subscribe to the connect event sioCom.Instance.On("connect", (string data) => { Debug.Log("LOCAL: Hey, we are connected!"); uiStatus.text = "Socket.IO Connected. Doing work..."; //NOTE: All those emitted and received events (except connect and disconnect) are made to showcase how this asset works. The technical handshake is done automatically. //First of all we knock at the servers door //EXAMPLE 1: Sending an event without payload data sioCom.Instance.Emit("KnockKnock"); }); //The server will respont to our knocking by askin who we are: //EXAMPLE 2: Listening for an event without payload sioCom.Instance.On("WhosThere", (string payload) => { //We will always receive a payload object as Socket.IO does not distinguish. In case the server sent nothing (as it will do in this example) the object will be null. if (payload == null) { Debug.Log("RECEIVED a WhosThere event without payload data just as expected."); } //As the server just asked for who we are, let's be polite and answer him. //EXAMPLE 3: Sending an event with payload data ItsMeData me = new ItsMeData() { version = Application.unityVersion }; sioCom.Instance.Emit("ItsMe", JsonUtility.ToJson(me), false); //Please note the third parameter which is semi-required if JSON.Net is not installed }); //The server will now receive our event and parse the data we sent. Then it will answer with two events. //EXAMPLE 4: Listening for an event with plain text payload sioCom.Instance.On("Welcome", (string payload) => { Debug.Log("SERVER: " + payload); uiGreeting.text = payload; }); //EXAMPLE 5: Listening for an event with JSON Object payload sioCom.Instance.On("TechData", (string payload) => { ServerTechData srv = JsonUtility.FromJson <ServerTechData>(payload); Debug.Log("Received the POD name from the server. Upadting UI. Oh! It's " + srv.timestamp + " by the way."); uiPodName.text = "I talked to " + srv.podName; //Let's ask for random numbers (example 6 below) sioCom.Instance.Emit("SendNumbers"); }); //EXAMPLE 6: Listening for an event with JSON Array payload sioCom.Instance.On("RandomNumbers", (string payload) => { Debug.Log("We received the following JSON payload from the server for example 6: " + payload); //Please note that unity's JsonUtility is not able to parse JSON arrays. You would need JSON.Net for this task. //This is how it works - if Json.NET is installed: #if HAS_JSON_NET int[] numbers = JsonConvert.DeserializeObject <int[]>(payload); Debug.Log("Thanks to Json.NET we were able to decode the numbers: " + string.Join(", ", numbers)); #endif //Send a goodbye to the server sioCom.Instance.Emit("Goodbye", "Thanks for talking to me!", true); //Please note the third parameter which is semi-required if JSON.Net is not installed }); //When the conversation is done, the server will close our connection after we said Goodbye sioCom.Instance.On("disconnect", (string payload) => { if (payload.Equals("io server disconnect")) { Debug.Log("Disconnected from server."); uiStatus.text = "Finished. Server closed connection."; } else { Debug.LogWarning("We have been unexpecteldy disconnected. This will cause an automatic reconnect. Reason: " + payload); } }); //We are now ready to actually connect //The simnple way will use the parameters set in the inspector (or with a former call to Connect(...)): //sioCom.Instance.Connect(); //For this example we will also show how to transmit a token or other data for authentication purposes: //PLEASE NOTE: You can only transmit primitives using the "authPayload". int, string, float... SIOAuthPayload auth = new SIOAuthPayload(); auth.AddElement("id", 1234); //The server will access this using socket.handshake.auth.id auth.AddElement("token", "UnitySample-abc123zyx"); //The server will access this using socket.handshake.auth.token //You could again use the component config for the target by using //sioCom.Instance.Connect(auth); //But the following command shows how you can programmatically connect to any server at any given time - in this case including our previously set auth information sioCom.Instance.Connect("https://sio-v4-example.unityassets.i01.clu.firesplash.de", false, auth); }