From 860b59ac7dd1a95cf5f9293b7d43167b62c99572 Mon Sep 17 00:00:00 2001 From: Abdullah Saleem Date: Sun, 5 Apr 2015 15:41:26 +0500 Subject: [PATCH 1/3] Configurable KeepAlive added --- Client/Client.csproj | 1 + Client/Core/Client.cs | 6 ++- Client/Core/Misc/KeepAlive.cs | 79 +++++++++++++++++++++++++++++++++++ Server/Core/Client.cs | 8 +++- Server/Core/Misc/KeepAlive.cs | 79 +++++++++++++++++++++++++++++++++++ Server/Server.csproj | 1 + 6 files changed, 172 insertions(+), 2 deletions(-) create mode 100644 Client/Core/Misc/KeepAlive.cs create mode 100644 Server/Core/Misc/KeepAlive.cs diff --git a/Client/Client.csproj b/Client/Client.csproj index 14d5f1d1..b538096b 100644 --- a/Client/Client.csproj +++ b/Client/Client.csproj @@ -63,6 +63,7 @@ + diff --git a/Client/Core/Client.cs b/Client/Core/Client.cs index 30174d40..9ca8122b 100644 --- a/Client/Core/Client.cs +++ b/Client/Core/Client.cs @@ -70,6 +70,9 @@ public enum ReceiveType Payload } + public const uint KEEP_ALIVE_TIME = 5000; + public const uint KEEP_ALIVE_INTERVAL = 5000; + public const int HEADER_SIZE = 4; public const int MAX_PACKET_SIZE = (1024 * 1024) * 1; //1MB private Socket _handle; @@ -102,7 +105,8 @@ public void Connect(string host, ushort port) Initialize(); _handle = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - _handle.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); + //_handle.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); + Misc.KeepAliveEx.SetKeepAliveEx(_handle, KEEP_ALIVE_INTERVAL, KEEP_ALIVE_TIME); _handle.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.NoDelay, true); _handle.NoDelay = true; diff --git a/Client/Core/Misc/KeepAlive.cs b/Client/Core/Misc/KeepAlive.cs new file mode 100644 index 00000000..d71bc40d --- /dev/null +++ b/Client/Core/Misc/KeepAlive.cs @@ -0,0 +1,79 @@ +using System; +using System.IO; +using System.Net.Sockets; +using System.Runtime.InteropServices; + +namespace xClient.Core.Misc +{ + /// + /// Socket Extension for KeepAlive + /// + /// Abdullah Saleem + /// a.saleem2993@gmail.com + public static class KeepAliveEx + { + /// + /// Sets the Keep-Alive values for the current tcp connection + /// + /// Current socket instance + /// Specifies how often TCP repeats keep-alive transmissions when no response is received. TCP sends keep-alive transmissions to verify that idle connections are still active. This prevents TCP from inadvertently disconnecting active lines. + /// Specifies how often TCP sends keep-alive transmissions. TCP sends keep-alive transmissions to verify that an idle connection is still active. This entry is used when the remote system is responding to TCP. Otherwise, the interval between transmissions is determined by the value of the keepAliveInterval entry. + public static void SetKeepAliveEx( /*this */ Socket socket, uint keepAliveInterval, uint keepAliveTime) + //extension removed, Missing System.Core.dll + { + var keepAlive = new TcpKeepAlive + { + onoff = 1, + keepaliveinterval = keepAliveInterval, + keepalivetime = keepAliveTime + }; + int size = Marshal.SizeOf(keepAlive); + IntPtr keepAlivePtr = Marshal.AllocHGlobal(size); + Marshal.StructureToPtr(keepAlive, keepAlivePtr, true); + var buffer = new byte[size]; + Marshal.Copy(keepAlivePtr, buffer, 0, size); + Marshal.FreeHGlobal(keepAlivePtr); + socket.IOControl(IOControlCode.KeepAliveValues, buffer, null); + } + + /// + /// Sets the Keep-Alive values for the current tcp connection + /// + /// Current socket instance + /// Specifies how often TCP repeats keep-alive transmissions when no response is received. TCP sends keep-alive transmissions to verify that idle connections are still active. This prevents TCP from inadvertently disconnecting active lines. + /// Specifies how often TCP sends keep-alive transmissions. TCP sends keep-alive transmissions to verify that an idle connection is still active. This entry is used when the remote system is responding to TCP. Otherwise, the interval between transmissions is determined by the value of the keepAliveInterval entry. + public static void SetKeepAlive(Socket socket, uint keepAliveInterval, uint keepAliveTime) + { + // //Removed, LINQ + // //byte[] dataWord = + // // (new byte[] { 0x01, 0x00, 0x00, 0x00 }).Concat(BitConverter.GetBytes(keepAliveTime)) + // // .Concat(BitConverter.GetBytes(keepAliveInterval)) + // // .ToArray(); + + byte[] dataWord; + using (var memoryStream = new MemoryStream()) + { + using (var binaryWriter = new BinaryWriter(memoryStream)) + { + binaryWriter.Write(new byte[] {0x01, 0x00, 0x00, 0x00}); + binaryWriter.Write(keepAliveTime); + binaryWriter.Write(keepAliveInterval); + } + dataWord = memoryStream.ToArray(); + } + socket.IOControl(IOControlCode.KeepAliveValues, dataWord, null); + } + + + /// + /// A structure used by SetKeepAliveEx(obsolete) Method + /// + [StructLayout(LayoutKind.Sequential)] + internal struct TcpKeepAlive + { + internal uint onoff; + internal uint keepalivetime; + internal uint keepaliveinterval; + }; + } +} \ No newline at end of file diff --git a/Server/Core/Client.cs b/Server/Core/Client.cs index eaff934c..55c0c03a 100644 --- a/Server/Core/Client.cs +++ b/Server/Core/Client.cs @@ -58,6 +58,9 @@ public enum ReceiveType Payload } + public const uint KEEP_ALIVE_TIME = 5000; + public const uint KEEP_ALIVE_INTERVAL = 5000; + public const int HEADER_SIZE = 4; public const int MAX_PACKET_SIZE = (1024 * 1024) * 1; //1MB private Socket _handle; @@ -94,7 +97,10 @@ internal Client(Server server, Socket sock, Type[] packets) _handle = sock; - _handle.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); + //_handle.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); + + Misc.KeepAliveEx.SetKeepAliveEx(_handle,KEEP_ALIVE_INTERVAL,KEEP_ALIVE_TIME); + _handle.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.NoDelay, true); _handle.NoDelay = true; diff --git a/Server/Core/Misc/KeepAlive.cs b/Server/Core/Misc/KeepAlive.cs new file mode 100644 index 00000000..4bebcbfb --- /dev/null +++ b/Server/Core/Misc/KeepAlive.cs @@ -0,0 +1,79 @@ +using System; +using System.IO; +using System.Net.Sockets; +using System.Runtime.InteropServices; + +namespace xServer.Core.Misc +{ + /// + /// Socket Extension for KeepAlive + /// + /// Abdullah Saleem + /// a.saleem2993@gmail.com + public static class KeepAliveEx + { + /// + /// Sets the Keep-Alive values for the current tcp connection + /// + /// Current socket instance + /// Specifies how often TCP repeats keep-alive transmissions when no response is received. TCP sends keep-alive transmissions to verify that idle connections are still active. This prevents TCP from inadvertently disconnecting active lines. + /// Specifies how often TCP sends keep-alive transmissions. TCP sends keep-alive transmissions to verify that an idle connection is still active. This entry is used when the remote system is responding to TCP. Otherwise, the interval between transmissions is determined by the value of the keepAliveInterval entry. + public static void SetKeepAliveEx( /*this */ Socket socket, uint keepAliveInterval, uint keepAliveTime) + //extension removed, Missing System.Core.dll + { + var keepAlive = new TcpKeepAlive + { + onoff = 1, + keepaliveinterval = keepAliveInterval, + keepalivetime = keepAliveTime + }; + int size = Marshal.SizeOf(keepAlive); + IntPtr keepAlivePtr = Marshal.AllocHGlobal(size); + Marshal.StructureToPtr(keepAlive, keepAlivePtr, true); + var buffer = new byte[size]; + Marshal.Copy(keepAlivePtr, buffer, 0, size); + Marshal.FreeHGlobal(keepAlivePtr); + socket.IOControl(IOControlCode.KeepAliveValues, buffer, null); + } + + /// + /// Sets the Keep-Alive values for the current tcp connection + /// + /// Current socket instance + /// Specifies how often TCP repeats keep-alive transmissions when no response is received. TCP sends keep-alive transmissions to verify that idle connections are still active. This prevents TCP from inadvertently disconnecting active lines. + /// Specifies how often TCP sends keep-alive transmissions. TCP sends keep-alive transmissions to verify that an idle connection is still active. This entry is used when the remote system is responding to TCP. Otherwise, the interval between transmissions is determined by the value of the keepAliveInterval entry. + public static void SetKeepAlive(Socket socket, uint keepAliveInterval, uint keepAliveTime) + { + // //Removed, LINQ + // //byte[] dataWord = + // // (new byte[] { 0x01, 0x00, 0x00, 0x00 }).Concat(BitConverter.GetBytes(keepAliveTime)) + // // .Concat(BitConverter.GetBytes(keepAliveInterval)) + // // .ToArray(); + + byte[] dataWord; + using (var memoryStream = new MemoryStream()) + { + using (var binaryWriter = new BinaryWriter(memoryStream)) + { + binaryWriter.Write(new byte[] { 0x01, 0x00, 0x00, 0x00 }); + binaryWriter.Write(keepAliveTime); + binaryWriter.Write(keepAliveInterval); + } + dataWord = memoryStream.ToArray(); + } + socket.IOControl(IOControlCode.KeepAliveValues, dataWord, null); + } + + + /// + /// A structure used by SetKeepAliveEx(obsolete) Method + /// + [StructLayout(LayoutKind.Sequential)] + internal struct TcpKeepAlive + { + internal uint onoff; + internal uint keepalivetime; + internal uint keepaliveinterval; + }; + } +} diff --git a/Server/Server.csproj b/Server/Server.csproj index 16e0e41e..92d8a106 100644 --- a/Server/Server.csproj +++ b/Server/Server.csproj @@ -384,6 +384,7 @@ Resources.resx True + SettingsSingleFileGenerator Settings.Designer.cs From 46bd17c4fa47923d403a2064eb293c93688051a6 Mon Sep 17 00:00:00 2001 From: Abdullah Saleem Date: Mon, 6 Apr 2015 22:12:56 +0500 Subject: [PATCH 2/3] Cross-Thread exception handled Cross-Thread exception on Uninstall --- Server/Core/Commands/CommandHandler.cs | 39 +++++++++++++------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/Server/Core/Commands/CommandHandler.cs b/Server/Core/Commands/CommandHandler.cs index a42dd2f6..ea4dd20c 100644 --- a/Server/Core/Commands/CommandHandler.cs +++ b/Server/Core/Commands/CommandHandler.cs @@ -1,6 +1,7 @@ using System; using System.Drawing; using System.IO; +using System.Runtime.InteropServices; using System.Threading; using System.Windows.Forms; using xServer.Core.Helper; @@ -68,27 +69,27 @@ private static void ShowPopup(Client c) FrmMain.Instance.nIcon.ShowBalloonTip(30, string.Format("Client connected from {0}!", c.Value.Country), string.Format("IP Address: {0}\nOperating System: {1}", c.EndPoint.Address.ToString(), c.Value.OperatingSystem), ToolTipIcon.Info); } - public static void HandleStatus(Client client, Status packet) - { - new Thread(() => - { - foreach (ListViewItem lvi in FrmMain.Instance.lstClients.Items) - { - Client c = (Client)lvi.Tag; - if (client == c) - { - FrmMain.Instance.Invoke((MethodInvoker)delegate - { - lvi.SubItems[3].Text = packet.Message; - }); - break; - } - } + public static void HandleStatus(Client client, Status packet) + { + new Thread(() => + { + FrmMain.Instance.Invoke((MethodInvoker) delegate + { + foreach (ListViewItem lvi in FrmMain.Instance.lstClients.Items) + { + Client c = (Client) lvi.Tag; + if (client == c) + { + lvi.SubItems[3].Text = packet.Message; + break; + } + } + }); - }).Start(); - } + }).Start(); + } - public static void HandleUserStatus(Client client, UserStatus packet) + public static void HandleUserStatus(Client client, UserStatus packet) { new Thread(() => { From 957ae2c0efd0d9d404615a41e1b69d1476440792 Mon Sep 17 00:00:00 2001 From: Abdullah Saleem Date: Mon, 6 Apr 2015 22:40:54 +0500 Subject: [PATCH 3/3] New KeepAlive Added Previous method of keep alive removed. --- Client/Config/Settings.cs | 2 +- Client/Core/Client.cs | 102 ++++++++++++++++++------------------ Server/Core/Client.cs | 18 +++---- Server/Core/Server.cs | 106 +++++++++++++++++++------------------- 4 files changed, 114 insertions(+), 114 deletions(-) diff --git a/Client/Config/Settings.cs b/Client/Config/Settings.cs index 32aeee7b..3b835209 100644 --- a/Client/Config/Settings.cs +++ b/Client/Config/Settings.cs @@ -9,7 +9,7 @@ public static class Settings { #if DEBUG public static string VERSION = "1.0.0.0d"; - public static string HOST = "localhost"; + public static string HOST = "192.168.1.11"; public static ushort PORT = 4782; public static int RECONNECTDELAY = 5000; public static string PASSWORD = "1234"; diff --git a/Client/Core/Client.cs b/Client/Core/Client.cs index 9ca8122b..237a9c58 100644 --- a/Client/Core/Client.cs +++ b/Client/Core/Client.cs @@ -116,7 +116,7 @@ public void Connect(string host, ushort port) { _handle.BeginReceive(this._buffer, 0, this._buffer.Length, SocketFlags.None, AsyncReceive, null); - SendKeepAlives(); + //SendKeepAlives(); OnClientState(true); } } @@ -129,13 +129,13 @@ public void Connect(string host, ushort port) private void Initialize() { - _keepAlives = new List(); + //_keepAlives = new List(); AddTypesToSerializer(typeof(IPacket), new Type[] { typeof(UnknownPacket), - typeof(KeepAlive), - typeof(KeepAliveResponse) + //typeof(KeepAlive), + //typeof(KeepAliveResponse) }); } @@ -196,11 +196,11 @@ private void AsyncReceive(IAsyncResult result) IPacket packet = Serializer.DeserializeWithLengthPrefix(deserialized, PrefixStyle.Fixed32); - if (packet.GetType() == typeof (KeepAlive)) - new KeepAliveResponse() {TimeSent = ((KeepAlive) packet).TimeSent}.Execute(this); - else if (packet.GetType() == typeof (KeepAliveResponse)) - HandleKeepAlivePacket((KeepAliveResponse) packet, this); - else + //if (packet.GetType() == typeof (KeepAlive)) + // new KeepAliveResponse() {TimeSent = ((KeepAlive) packet).TimeSent}.Execute(this); + //else if (packet.GetType() == typeof (KeepAliveResponse)) + // HandleKeepAlivePacket((KeepAliveResponse) packet, this); + //else OnClientRead(packet); } } @@ -336,52 +336,52 @@ public void AddTypesToSerializer(Type parent, params Type[] types) AddTypeToSerializer(parent, type); } - private void HandleKeepAlivePacket(KeepAliveResponse packet, Client client) - { - foreach (KeepAlive keepAlive in _keepAlives) - { - if (keepAlive.TimeSent == packet.TimeSent && keepAlive.Client == client) - { - _keepAlives.Remove(keepAlive); - break; - } - } - } + //private void HandleKeepAlivePacket(KeepAliveResponse packet, Client client) + //{ + // foreach (KeepAlive keepAlive in _keepAlives) + // { + // if (keepAlive.TimeSent == packet.TimeSent && keepAlive.Client == client) + // { + // _keepAlives.Remove(keepAlive); + // break; + // } + // } + //} - private void KeepAliveCallback(object state) - { - KeepAlive keepAlive = (KeepAlive)state; + //private void KeepAliveCallback(object state) + //{ + // KeepAlive keepAlive = (KeepAlive)state; - if (_keepAlives.Contains(keepAlive)) - { - Disconnect(); - } - } + // if (_keepAlives.Contains(keepAlive)) + // { + // Disconnect(); + // } + //} - private void SendKeepAlives() - { - new Thread(() => - { - while (Connected) - { - try - { - KeepAlive keepAlive = new KeepAlive(); - lock (_keepAlives) - { - _keepAlives.Add(keepAlive); - } - keepAlive.Execute(this); - Timer timer = new Timer(KeepAliveCallback, keepAlive, 25000, Timeout.Infinite); - } - catch - { + //private void SendKeepAlives() + //{ + // new Thread(() => + // { + // while (Connected) + // { + // try + // { + // KeepAlive keepAlive = new KeepAlive(); + // lock (_keepAlives) + // { + // _keepAlives.Add(keepAlive); + // } + // keepAlive.Execute(this); + // Timer timer = new Timer(KeepAliveCallback, keepAlive, 25000, Timeout.Infinite); + // } + // catch + // { - } - Thread.Sleep(15000); - } + // } + // Thread.Sleep(15000); + // } - }) { IsBackground = true }.Start(); - } + // }) { IsBackground = true }.Start(); + //} } } diff --git a/Server/Core/Client.cs b/Server/Core/Client.cs index 55c0c03a..181c85f0 100644 --- a/Server/Core/Client.cs +++ b/Server/Core/Client.cs @@ -58,8 +58,8 @@ public enum ReceiveType Payload } - public const uint KEEP_ALIVE_TIME = 5000; - public const uint KEEP_ALIVE_INTERVAL = 5000; + public const uint KEEP_ALIVE_TIME = 1000; + public const uint KEEP_ALIVE_INTERVAL = 1000; public const int HEADER_SIZE = 4; public const int MAX_PACKET_SIZE = (1024 * 1024) * 1; //1MB @@ -119,8 +119,8 @@ private void Initialize() AddTypesToSerializer(typeof(IPacket), new Type[] { typeof(UnknownPacket), - typeof(KeepAlive), - typeof(KeepAliveResponse) + //typeof(KeepAlive), + //typeof(KeepAliveResponse) }); } @@ -183,11 +183,11 @@ private void AsyncReceive(IAsyncResult result) IPacket packet = Serializer.DeserializeWithLengthPrefix(deserialized, PrefixStyle.Fixed32); - if (packet.GetType() == typeof (KeepAlive)) - new KeepAliveResponse() {TimeSent = ((KeepAlive) packet).TimeSent}.Execute(this); - else if (packet.GetType() == typeof (KeepAliveResponse)) - _parentServer.HandleKeepAlivePacket((KeepAliveResponse) packet, this); // HERE - else + //if (packet.GetType() == typeof (KeepAlive)) + // new KeepAliveResponse() {TimeSent = ((KeepAlive) packet).TimeSent}.Execute(this); + //else if (packet.GetType() == typeof (KeepAliveResponse)) + // _parentServer.HandleKeepAlivePacket((KeepAliveResponse) packet, this); // HERE + //else OnClientRead(packet); } } diff --git a/Server/Core/Server.cs b/Server/Core/Server.cs index 23ca21d1..3fde10d1 100644 --- a/Server/Core/Server.cs +++ b/Server/Core/Server.cs @@ -66,7 +66,7 @@ private void OnClientWrite(Client c, IPacket packet, long length, byte[] rawData public bool Listening { get; private set; } - private List _keepAlives; + // private List _keepAlives; private List _clients; public Client[] Clients @@ -94,7 +94,7 @@ public void Listen(ushort port) { if (!Listening) { - _keepAlives = new List(); + // _keepAlives = new List(); _clients = new List(); @@ -111,7 +111,7 @@ public void Listen(ushort port) OnServerState(true); - SendKeepAlives(); + // SendKeepAlives(); if (!_handle.AcceptAsync(_item)) Process(null, _item); @@ -173,60 +173,60 @@ private void Process(object s, SocketAsyncEventArgs e) } } - private void SendKeepAlives() - { - new Thread(() => - { - while (true) - { - try - { - foreach (Client client in Clients) - { - KeepAlive keepAlive = new KeepAlive(); - lock (_keepAlives) - { - _keepAlives.Add(keepAlive); - } - keepAlive.Execute(client); - Timer timer = new Timer(KeepAliveCallback, keepAlive, 15000, Timeout.Infinite); - } - } - catch - { + //private void SendKeepAlives() + //{ + // new Thread(() => + // { + // while (true) + // { + // try + // { + // foreach (Client client in Clients) + // { + // KeepAlive keepAlive = new KeepAlive(); + // lock (_keepAlives) + // { + // _keepAlives.Add(keepAlive); + // } + // keepAlive.Execute(client); + // Timer timer = new Timer(KeepAliveCallback, keepAlive, 15000, Timeout.Infinite); + // } + // } + // catch + // { - } - Thread.Sleep(10000); - } + // } + // Thread.Sleep(10000); + // } - }) { IsBackground = true }.Start(); - } + // }) { IsBackground = true }.Start(); + //} - private void KeepAliveCallback(object state) - { - KeepAlive keepAlive = (KeepAlive)state; + //private void KeepAliveCallback(object state) + //{ + // KeepAlive keepAlive = (KeepAlive)state; - if (_keepAlives != null) - { - if (_keepAlives.Contains(keepAlive)) - { - keepAlive.Client.Disconnect(); - _keepAlives.Remove(keepAlive); - } - } - } + // if (_keepAlives != null) + // { + // if (_keepAlives.Contains(keepAlive)) + // { + // keepAlive.Client.Disconnect(); + // _keepAlives.Remove(keepAlive); + // } + // } + //} - internal void HandleKeepAlivePacket(KeepAliveResponse packet, Client client) - { - foreach (KeepAlive keepAlive in _keepAlives) - { - if (keepAlive.TimeSent == packet.TimeSent && keepAlive.Client == client) - { - _keepAlives.Remove(keepAlive); - break; - } - } - } + //internal void HandleKeepAlivePacket(KeepAliveResponse packet, Client client) + //{ + // foreach (KeepAlive keepAlive in _keepAlives) + // { + // if (keepAlive.TimeSent == packet.TimeSent && keepAlive.Client == client) + // { + // _keepAlives.Remove(keepAlive); + // break; + // } + // } + //} public void Disconnect() { @@ -252,7 +252,7 @@ public void Disconnect() } } - _keepAlives = null; + // _keepAlives = null; Listening = false; OnServerState(false);