internal bool ProcessAdvancedMessage(NetCoreMessage _message) { NetCoreAdvancedMessage message; if (_message is NetCoreAdvancedMessage) { message = (_message as NetCoreAdvancedMessage); } else { message = new NetCoreAdvancedMessage(_message.Type); // promote message to Advanced if simple ({BOOP} command goes through UDP Link) } if (!message.Type.StartsWith("{EVENT_") || ConsoleEx.ShowDebug) { ConsoleEx.WriteLine(spec.Side.ToString() + ":Process advanced message -> " + message.Type.ToString()); } switch (message.Type) { // NetCore Internal Commands // Some of these commands go through the UDP Link but are upgraded to an Advanced Message // As they are parsed by the Message Hub case "{HI}": //Greetings to confirm that communication is established expectingSomeone = true; status = NetworkStatus.CONNECTED; if (spec.Side == NetworkSide.SERVER) { //Server receives {HI} after client has established connection ConsoleEx.WriteLine($"TCP Server Connected"); //spec.OnServerConnected(null); spec.Connector.hub.QueueMessage(new NetCoreAdvancedMessage("{EVENT_SERVERCONNECTED}")); SendMessage(new NetCoreAdvancedMessage("{HI}")); } else //(side == NetworkSide.CLIENT) { //Client always sends the first {HI} but will wait for the Server to reply with one ConsoleEx.WriteLine($"TCP Client Connected to {IP}:{Port}"); //spec.OnClientConnected(null); spec.Connector.hub.QueueMessage(new NetCoreAdvancedMessage("{EVENT_CLIENTCONNECTED}")); } break; case "{BYE}": // End of disconnect Kill(); break; case "{BOOP}": // Ping system to confirm is TCP link is still in order // Boops are redirected through the UDP pipe so if the TCP Link is busy transfering a lot of data // or is jammed waiting for a return, these will still go through BoopMonitoringCounter = DefaultBoopMonitoringCounter; break; //THREADSAFE EVENT FIRING case "{EVENT_CLIENTCONNECTING}": spec.OnClientConnecting(null); break; case "{EVENT_CLIENTCONNECTINGFAILED}": spec.OnClientConnectingFailed(null); break; case "{EVENT_CLIENTCONNECTED}": spec.OnClientConnected(null); break; case "{EVENT_CLIENTDISCONNECTED}": spec.OnClientDisconnected(null); break; case "{EVENT_CLIENTCONNECTIONLOST}": spec.OnClientConnectionLost(null); break; case "{EVENT_SERVERLISTENING}": spec.OnServerListening(null); break; case "{EVENT_SERVERCONNECTED}": spec.OnServerConnected(null); break; case "{EVENT_SERVERDISCONNECTED}": spec.OnServerDisconnected(null); break; case "{EVENT_SERVERCONNECTIONLOST}": spec.OnServerConnectionLost(null); break; case "{EVENT_SYNCEDMESSAGESTART}": spec.OnSyncedMessageStart(null); break; case "{EVENT_SYNCEDMESSAGEEND}": spec.OnSyncedMessageEnd(null); break; default: //If message wasn't procesed, just return false //Message may be handled on an upper level return(false); } return(true); }
private bool StartClient() { client = new TcpClient(); TcpClient clientRef = client; try { IAsyncResult result = null; bool success = false; try { result = client.BeginConnect(IP, Port, null, null); success = result.AsyncWaitHandle.WaitOne(TimeSpan.FromMilliseconds(200)); //This will block the thread for 200ms } catch { } if (!success || result == null || client == null) { throw new Exception("Failed to connect"); } client.EndConnect(result); clientStream = client.GetStream(); if (streamReadingThread != null) { streamReadingThread.Abort(); while (streamReadingThread != null && streamReadingThread.IsAlive) { System.Windows.Forms.Application.DoEvents(); Thread.Sleep(10); } //Lets wait for the thread to die } streamReadingThread = new Thread(() => StoreMessages(clientStream)); streamReadingThread.Name = "TCP CLIENT"; streamReadingThread.IsBackground = true; streamReadingThread.Start(); ConsoleEx.WriteLine($"Started new TCPLink Thread for CLIENT"); } catch (Exception ex) { if (ex.Message != "Failed to connect") { DiscardException(ex); } try { clientStream?.Close(); clientStream = null; } catch { } try { if (Object.ReferenceEquals(clientRef, client)) { client?.Close(); client = null; } } catch { } status = NetworkStatus.DISCONNECTED; ConsoleEx.WriteLine($"Connecting Failed"); spec.Connector.hub.QueueMessage(new NetCoreAdvancedMessage("{EVENT_CLIENTCONNECTINGFAILED}")); //spec.OnClientConnectingFailed(null); return(false); } return(true); }
private void DiscardException(Exception ex) { //Discarded exception but write it in console ConsoleEx.WriteLine($"{spec.Side}:{status} -> {ex}"); }
internal void StopNetworking(bool stopGracefully = true, bool stayConnected = false) { TcpClient clientRef = client; if (stopGracefully) { //If this is a graceful stop, try to say {BYE} before leaving lock (PeerMessageQueueLock) { PeerMessageQueue.Clear(); spec.Connector.hub.SendMessage(new NetCoreAdvancedMessage("{BYE}")); //When the {BYE} command gets sent, a {SAYBYE} command will be queued in own side's Message Hub. //Both sides will then call StopNetworking with the stopGracefully flag set to false. } return; } BoopMonitoringTimer?.Stop(); BoopMonitoringTimer = null; supposedToBeConnected = false; if (!stayConnected) { expectingSomeone = false; } if (spec.Side == NetworkSide.CLIENT && (status == NetworkStatus.CONNECTED || status == NetworkStatus.CONNECTING)) { if (stayConnected) { ConsoleEx.WriteLine($"TCP Client Connection Lost"); //spec.OnClientConnectionLost(null); spec.Connector.hub.QueueMessage(new NetCoreAdvancedMessage("{EVENT_CLIENTCONNECTIONLOST}")); } else { ConsoleEx.WriteLine($"TCP Client Disconnected"); //spec.OnClientDisconnected(null); spec.Connector.hub.QueueMessage(new NetCoreAdvancedMessage("{EVENT_CLIENTDISCONNECTED}")); } } else if (spec.Side == NetworkSide.SERVER && (status == NetworkStatus.CONNECTED || status == NetworkStatus.LISTENING)) { if (stayConnected) { ConsoleEx.WriteLine($"TCP Server Connection Lost"); //spec.OnServerConnectionLost(null); spec.Connector.hub.QueueMessage(new NetCoreAdvancedMessage("{EVENT_SERVERCONNECTIONLOST}")); } else { ConsoleEx.WriteLine($"TCP Server Disconnected"); //spec.OnServerDisconnected(null); spec.Connector.hub.QueueMessage(new NetCoreAdvancedMessage("{EVENT_SERVERDISCONNECTED}")); } } status = (stayConnected ? NetworkStatus.CONNECTIONLOST : NetworkStatus.DISCONNECTED); lock (PeerMessageQueueLock) PeerMessageQueue.Clear(); KillConnections(clientRef); spec.Connector.watch.Kill(); //Kills the ReturnWatch if waiting for a value }
private void StoreMessages(NetworkStream providedStream) { var binaryFormatter = new BinaryFormatter(); TcpListener server = null; Socket socket = null; NetworkStream networkStream = null; if (providedStream != null) { networkStream = providedStream; } try { if (networkStream == null) { server = new TcpListener((IP == "127.0.0.1" ? IPAddress.Loopback : IPAddress.Any), Port); server.Start(); socket = KillableAcceptSocket(server); networkStream = new NetworkStream(socket); server.Stop(); } networkStream.ReadTimeout = int.MaxValue; //We don't put a timeout because we can detect broken links networkStream.WriteTimeout = int.MaxValue; //Using {BOOP} commands routed through UDP/TCP if (spec.Side == NetworkSide.CLIENT) { SendMessage(new NetCoreAdvancedMessage("{HI}")); //The exchange of {HI} command confirms that link is established on Receiving } while (true) { if (networkStream != null && networkStream.DataAvailable) { NetCoreAdvancedMessage message; try { message = (NetCoreAdvancedMessage)binaryFormatter.Deserialize(networkStream); //This is blocking } catch { throw; } if (message != null) { if (message.Type == "{RETURNVALUE}") { spec.Connector.watch.AddReturn(message); } else { spec.Connector.hub.QueueMessage(message); } } } while (PeerMessageQueue.Count > 0) { NetCoreMessage pendingMessage; lock (PeerMessageQueueLock) { pendingMessage = PeerMessageQueue.First.Value; PeerMessageQueue.RemoveFirst(); } try { binaryFormatter.Serialize(networkStream, pendingMessage); } catch { throw; } if (pendingMessage.Type == "{BYE}") { lock (PeerMessageQueueLock) //Since we're shutting down, let's clear the message queue PeerMessageQueue.Clear(); } if (status == NetworkStatus.DISCONNECTED || status == NetworkStatus.CONNECTIONLOST) { //If the link's status changed from an outside factor, we want to stop the thread. lock (PeerMessageQueueLock) PeerMessageQueue.Clear(); return; } } Thread.Sleep(spec.messageReadTimerDelay); } } catch (Exception ex) { if (ex is ThreadAbortException) { ConsoleEx.WriteLine("Ongoing TCPLink Thread Killed"); } else if (ex.InnerException != null && ex.InnerException is SocketException) { ConsoleEx.WriteLine("Ongoing TCPLink Socket Closed during use"); } else if (ex is SerializationException) { ConsoleEx.WriteLine("Ongoing TCPLink Closed during Serialization operation"); } else if (ex is ObjectDisposedException) { ConsoleEx.WriteLine("Ongoing TCPLink Closed during Socket acceptance"); } else { DiscardException(ex); } } finally { //Let's force close everything JUST IN CASE try { networkStream.Close(); networkStream.Dispose(); } catch { } //nobody cares why this failed try { socket.Shutdown(SocketShutdown.Both); socket.Dispose(); } catch { } //nobody cares why this failed try { server.Stop(); } catch { } //nobody cares why this failed if (status == NetworkStatus.CONNECTED) { status = (expectingSomeone ? NetworkStatus.CONNECTIONLOST : NetworkStatus.DISCONNECTED); } else if (status != NetworkStatus.CONNECTIONLOST) { status = NetworkStatus.DISCONNECTED; } //Kill synced query if happenning spec.Connector.watch.Kill(); } }