private void ListenToReader() { int port = (spec.Side == NetworkSide.SERVER ? PortClient : PortServer); int UdpReceiveTimeout = 1000; UdpClient Listener = null; IPEndPoint groupEP = new IPEndPoint((IP == "127.0.0.1" ? IPAddress.Loopback : IPAddress.Any), port); try { Running = true; ConsoleEx.WriteLine($"UDP Server listening on Port {port}"); while (Running) { try { if (Listener == null) { Listener = new UdpClient(port); Listener.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, UdpReceiveTimeout); } } catch (SocketException ex) { if (ex.SocketErrorCode == SocketError.AddressAlreadyInUse) { ConsoleEx.WriteLine("UDP Socket Port Collision"); } else { ConsoleEx.WriteLine(ex.ToString()); } return; } catch (Exception ex) { ConsoleEx.WriteLine(ex.ToString()); return; } byte[] bytes = null; try { bytes = Listener.Receive(ref groupEP); } catch (SocketException ex) { if (ex.SocketErrorCode == SocketError.TimedOut) { Listener?.Client?.Close(); Listener?.Close(); Listener = null; continue; } else { throw ex; } } spec.Connector.hub.QueueMessage(new NetCoreSimpleMessage(Encoding.ASCII.GetString(bytes, 0, bytes.Length))); } } catch (ThreadAbortException) { ConsoleEx.WriteLine("Ongoing UDPLink Thread Killed"); } catch (Exception e) { ConsoleEx.WriteLine(e.ToString()); } finally { Listener?.Client?.Close(); Listener?.Close(); } }
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 (Exception ex) { Console.WriteLine(ex); } 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); }
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); }
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) { 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) { 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 DiscardException(Exception ex) { //Discarded exception but write it in console ConsoleEx.WriteLine($"{spec.Side}:{status} -> {ex} \n Supposed to be connected -> {supposedToBeConnected} \n expectingsomeone -> {expectingSomeone} \n status -> {status} \n {ex.StackTrace}"); }
private void StoreMessages(NetworkStream providedStream) { var config = new SerializerConfig(); config.Advanced.PersistTypeCache = true; config.OnResolveFormatter.Add((c, t) => { if (t == typeof(HashSet <byte[]>)) { return(new NetCore.NetCore_Extensions.HashSetFormatterThatKeepsItsComparer()); } return(null); // continue searching }); var serializer = new CerasSerializer(config); 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 = 20; 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) { if (spec.Side == NetworkSide.SERVER && (!socket?.Connected ?? true)) { return; } NetCoreAdvancedMessage message = null; try { using (MemoryStream ms = new MemoryStream()) { Stopwatch sw = new Stopwatch(); sw.Start(); //Read the size int lengthToReceive = 0; byte[] _lengthToReceive = new byte[4]; networkStream.Read(_lengthToReceive, 0, _lengthToReceive.Length); lengthToReceive = BitConverter.ToInt32(_lengthToReceive, 0); //Console.WriteLine("I want this many bytes: " + lengthToReceive); //Now read until we have that many bytes long bytesRead = CopyBytes(lengthToReceive, networkStream, ms); //Console.WriteLine("I got this many bytes: " + bytesRead); //Deserialize it ms.Position = 0; //cmd = (RTC_Command)binaryFormatter.Deserialize(ms); var temp = ms.ToArray(); message = serializer.Deserialize <NetCoreAdvancedMessage>(temp); sw.Stop(); if (message.Type != "{BOOP}" && sw.ElapsedMilliseconds > 50) { Console.WriteLine("It took " + sw.ElapsedMilliseconds + " ms to deserialize cmd " + message.Type + " of " + temp.Length + " bytes"); } } } 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 { Stopwatch sw = new Stopwatch(); sw.Start(); //Write the length of the command to the first four bytes byte[] buf = serializer.Serialize(pendingMessage); //Write the length of the incoming object to the NetworkStream byte[] length = BitConverter.GetBytes(buf.Length); networkStream.Write(length, 0, length.Length); networkStream.Write(buf, 0, buf.Length); sw.Stop(); if (pendingMessage.Type != "{BOOP}" && sw.ElapsedMilliseconds > 50) { Console.WriteLine("It took " + sw.ElapsedMilliseconds + " ms to serialize backCmd " + pendingMessage.Type + " of " + buf.Length + " bytes"); } } 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 (Exception ex) { DiscardException(ex); } 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(); } }
private void DiscardException(Exception ex) { //Discarded exception but write it in console ConsoleEx.WriteLine($"{spec.Side}:{status} -> {ex}"); }
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(); } }