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/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 3a9eca9a..fda2d52c 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; @@ -112,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); } } @@ -125,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) }); } @@ -192,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); } } @@ -334,52 +338,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/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..181c85f0 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 = 1000; + public const uint KEEP_ALIVE_INTERVAL = 1000; + 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; @@ -113,8 +119,8 @@ private void Initialize() AddTypesToSerializer(typeof(IPacket), new Type[] { typeof(UnknownPacket), - typeof(KeepAlive), - typeof(KeepAliveResponse) + //typeof(KeepAlive), + //typeof(KeepAliveResponse) }); } @@ -177,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/Commands/CommandHandler.cs b/Server/Core/Commands/CommandHandler.cs index a84a2e1d..a45a6443 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; @@ -67,27 +68,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(() => { 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/Core/Server.cs b/Server/Core/Server.cs index d8e56e26..60939d4e 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); 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