Fixes to networking code

This commit is contained in:
MaxXor 2015-09-09 00:19:48 +02:00
parent cc8bfddaf3
commit 6d72bef8d2
5 changed files with 116 additions and 121 deletions

View File

@ -7,12 +7,11 @@ using System.Threading;
using xServer.Core.Compression; using xServer.Core.Compression;
using xServer.Core.Cryptography; using xServer.Core.Cryptography;
using xServer.Core.Extensions; using xServer.Core.Extensions;
using xServer.Core.NetSerializer;
using xServer.Core.Packets; using xServer.Core.Packets;
namespace xServer.Core.Networking namespace xServer.Core.Networking
{ {
public class Client public class Client : IEquatable<Client>
{ {
/// <summary> /// <summary>
/// Occurs when the state of the client changes. /// Occurs when the state of the client changes.
@ -102,12 +101,13 @@ namespace xServer.Core.Networking
/// Checks whether the clients are equal. /// Checks whether the clients are equal.
/// </summary> /// </summary>
/// <param name="c">Client to compare with.</param> /// <param name="c">Client to compare with.</param>
/// <returns></returns> /// <returns>True if equal, else False.</returns>
public bool Equals(Client c) public bool Equals(Client c)
{ {
try try
{ {
return this.EndPoint.Port == c.EndPoint.Port; // this port is always unique for each client // the port is always unique for each client
return this.EndPoint.Port.Equals(c.EndPoint.Port);
} }
catch (Exception) catch (Exception)
{ {
@ -115,6 +115,30 @@ namespace xServer.Core.Networking
} }
} }
public override bool Equals(object obj)
{
return this.Equals(obj as Client);
}
public static bool operator ==(Client lhs, Client rhs)
{
return ReferenceEquals(lhs, null) ? ReferenceEquals(rhs, null) : lhs.Equals(rhs);
}
public static bool operator !=(Client lhs, Client rhs)
{
return !(lhs == rhs);
}
/// <summary>
/// Returns the hashcode for this instance.
/// </summary>
/// <returns>A hash code for the current instance.</returns>
public override int GetHashCode()
{
return this.EndPoint.Port.GetHashCode();
}
/// <summary> /// <summary>
/// The type of the packet received. /// The type of the packet received.
/// </summary> /// </summary>
@ -222,29 +246,17 @@ namespace xServer.Core.Networking
/// </summary> /// </summary>
private bool _appendHeader; private bool _appendHeader;
/// <summary>
/// The packet serializer.
/// </summary>
private Serializer _serializer;
private const bool encryptionEnabled = true; private const bool encryptionEnabled = true;
private const bool compressionEnabled = true; private const bool compressionEnabled = true;
public Client() public Client(Server parentServer, Socket socket)
{
}
internal Client(Server server, Socket sock, Type[] packets)
{ {
try try
{ {
_parentServer = server; _parentServer = parentServer;
_parentServer.AddClient(this);
AddTypesToSerializer(packets);
if (_serializer == null) throw new Exception("Serializer not initialized");
Initialize(); Initialize();
_handle = sock; _handle = socket;
_handle.SetKeepAliveEx(_parentServer.KEEP_ALIVE_INTERVAL, _parentServer.KEEP_ALIVE_TIME); _handle.SetKeepAliveEx(_parentServer.KEEP_ALIVE_INTERVAL, _parentServer.KEEP_ALIVE_TIME);
EndPoint = (IPEndPoint)_handle.RemoteEndPoint; EndPoint = (IPEndPoint)_handle.RemoteEndPoint;
@ -488,7 +500,7 @@ namespace xServer.Core.Networking
{ {
try try
{ {
IPacket packet = (IPacket)_serializer.Deserialize(deserialized); IPacket packet = (IPacket)_parentServer.Serializer.Deserialize(deserialized);
OnClientRead(packet); OnClientRead(packet);
} }
@ -538,7 +550,7 @@ namespace xServer.Core.Networking
{ {
using (MemoryStream ms = new MemoryStream()) using (MemoryStream ms = new MemoryStream())
{ {
_serializer.Serialize(ms, packet); _parentServer.Serializer.Serialize(ms, packet);
byte[] payload = ms.ToArray(); byte[] payload = ms.ToArray();
@ -665,23 +677,11 @@ namespace xServer.Core.Networking
Value.Dispose(); Value.Dispose();
Value = null; Value = null;
} }
if (_parentServer.BufferManager != null) _parentServer.BufferManager.ReturnBuffer(_readBuffer);
_parentServer.BufferManager.ReturnBuffer(_readBuffer);
} }
_parentServer.RemoveClient(this);
OnClientState(false); OnClientState(false);
} }
/// <summary>
/// Adds Types to the serializer.
/// </summary>
/// <param name="types">Types to add.</param>
public void AddTypesToSerializer(Type[] types)
{
_serializer = new Serializer(types);
}
} }
} }

View File

@ -1,10 +1,10 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Windows.Forms; using System.Windows.Forms;
using xServer.Core.Data; using xServer.Core.Data;
using xServer.Core.NetSerializer;
using xServer.Core.Networking.Utilities; using xServer.Core.Networking.Utilities;
using xServer.Core.Packets; using xServer.Core.Packets;
@ -29,7 +29,7 @@ namespace xServer.Core.Networking
/// Fires an event that informs subscribers that the server has changed it's state. /// Fires an event that informs subscribers that the server has changed it's state.
/// </summary> /// </summary>
/// <param name="listening">The new listening state of the server.</param> /// <param name="listening">The new listening state of the server.</param>
private void OnServerState(bool listening) protected void OnServerState(bool listening)
{ {
if (Listening == listening) return; if (Listening == listening) return;
@ -45,7 +45,7 @@ namespace xServer.Core.Networking
/// <summary> /// <summary>
/// Occurs when the state of a client changes. /// Occurs when the state of a client changes.
/// </summary> /// </summary>
protected event ClientStateEventHandler ClientState; public event ClientStateEventHandler ClientState;
/// <summary> /// <summary>
/// Represents a method that will handle a change in a client's state. /// Represents a method that will handle a change in a client's state.
@ -53,16 +53,20 @@ namespace xServer.Core.Networking
/// <param name="s">The server, the client is connected to.</param> /// <param name="s">The server, the client is connected to.</param>
/// <param name="c">The client which changed its state.</param> /// <param name="c">The client which changed its state.</param>
/// <param name="connected">The new connection state of the client.</param> /// <param name="connected">The new connection state of the client.</param>
protected delegate void ClientStateEventHandler(Server s, Client c, bool connected); public delegate void ClientStateEventHandler(Server s, Client c, bool connected);
/// <summary> /// <summary>
/// Fires an event that informs subscribers that a client has changed its state. /// Fires an event that informs subscribers that a client has changed its state.
/// </summary> /// </summary>
/// <param name="c">The client which changed its state.</param> /// <param name="c">The client which changed its state.</param>
/// <param name="connected">The new connection state of the client.</param> /// <param name="connected">The new connection state of the client.</param>
private void OnClientState(Client c, bool connected) protected void OnClientState(Client c, bool connected)
{ {
var handler = ClientState; var handler = ClientState;
if (!connected)
RemoveClient(c);
if (handler != null) if (handler != null)
{ {
handler(this, c, connected); handler(this, c, connected);
@ -72,7 +76,7 @@ namespace xServer.Core.Networking
/// <summary> /// <summary>
/// Occurs when a packet is received by a client. /// Occurs when a packet is received by a client.
/// </summary> /// </summary>
protected event ClientReadEventHandler ClientRead; public event ClientReadEventHandler ClientRead;
/// <summary> /// <summary>
/// Represents a method that will handle a packet received from a client. /// Represents a method that will handle a packet received from a client.
@ -80,7 +84,7 @@ namespace xServer.Core.Networking
/// <param name="s">The server, the client is connected to.</param> /// <param name="s">The server, the client is connected to.</param>
/// <param name="c">The client that has received the packet.</param> /// <param name="c">The client that has received the packet.</param>
/// <param name="packet">The packet that received by the client.</param> /// <param name="packet">The packet that received by the client.</param>
protected delegate void ClientReadEventHandler(Server s, Client c, IPacket packet); public delegate void ClientReadEventHandler(Server s, Client c, IPacket packet);
/// <summary> /// <summary>
/// Fires an event that informs subscribers that a packet has been /// Fires an event that informs subscribers that a packet has been
@ -88,7 +92,7 @@ namespace xServer.Core.Networking
/// </summary> /// </summary>
/// <param name="c">The client that has received the packet.</param> /// <param name="c">The client that has received the packet.</param>
/// <param name="packet">The packet that received by the client.</param> /// <param name="packet">The packet that received by the client.</param>
private void OnClientRead(Client c, IPacket packet) protected void OnClientRead(Client c, IPacket packet)
{ {
var handler = ClientRead; var handler = ClientRead;
if (handler != null) if (handler != null)
@ -100,7 +104,7 @@ namespace xServer.Core.Networking
/// <summary> /// <summary>
/// Occurs when a packet is sent by a client. /// Occurs when a packet is sent by a client.
/// </summary> /// </summary>
protected event ClientWriteEventHandler ClientWrite; public event ClientWriteEventHandler ClientWrite;
/// <summary> /// <summary>
/// Represents the method that will handle the sent packet by a client. /// Represents the method that will handle the sent packet by a client.
@ -110,7 +114,7 @@ namespace xServer.Core.Networking
/// <param name="packet">The packet that has been sent by the client.</param> /// <param name="packet">The packet that has been sent by the client.</param>
/// <param name="length">The length of the packet.</param> /// <param name="length">The length of the packet.</param>
/// <param name="rawData">The packet in raw bytes.</param> /// <param name="rawData">The packet in raw bytes.</param>
protected delegate void ClientWriteEventHandler(Server s, Client c, IPacket packet, long length, byte[] rawData); public delegate void ClientWriteEventHandler(Server s, Client c, IPacket packet, long length, byte[] rawData);
/// <summary> /// <summary>
/// Fires an event that informs subscribers that the client has sent a packet. /// Fires an event that informs subscribers that the client has sent a packet.
@ -119,7 +123,7 @@ namespace xServer.Core.Networking
/// <param name="packet">The packet that has been sent by the client.</param> /// <param name="packet">The packet that has been sent by the client.</param>
/// <param name="length">The length of the packet.</param> /// <param name="length">The length of the packet.</param>
/// <param name="rawData">The packet in raw bytes.</param> /// <param name="rawData">The packet in raw bytes.</param>
private void OnClientWrite(Client c, IPacket packet, long length, byte[] rawData) protected void OnClientWrite(Client c, IPacket packet, long length, byte[] rawData)
{ {
var handler = ClientWrite; var handler = ClientWrite;
if (handler != null) if (handler != null)
@ -188,11 +192,16 @@ namespace xServer.Core.Networking
{ {
lock (_clientsLock) lock (_clientsLock)
{ {
return Listening ? _clients.ToArray() : new Client[0]; return _clients.ToArray();
} }
} }
} }
/// <summary>
/// The packet serializer.
/// </summary>
public Serializer Serializer { get; protected set; }
/// <summary> /// <summary>
/// Handle of the Server Socket. /// Handle of the Server Socket.
/// </summary> /// </summary>
@ -213,11 +222,6 @@ namespace xServer.Core.Networking
/// </summary> /// </summary>
private readonly object _clientsLock = new object(); private readonly object _clientsLock = new object();
/// <summary>
/// List of all supported Packet Types by the server.
/// </summary>
private List<Type> PacketTypes { get; set; }
/// <summary> /// <summary>
/// Determines if the server is currently processing Disconnect method. /// Determines if the server is currently processing Disconnect method.
/// </summary> /// </summary>
@ -226,9 +230,10 @@ namespace xServer.Core.Networking
/// <summary> /// <summary>
/// Constructor of the server, initializes variables. /// Constructor of the server, initializes variables.
/// </summary> /// </summary>
public Server() protected Server()
{ {
PacketTypes = new List<Type>(); _clients = new List<Client>();
BufferManager = new PooledBufferManager(BUFFER_SIZE, 1) { ClearOnReturn = false };
} }
/// <summary> /// <summary>
@ -237,29 +242,17 @@ namespace xServer.Core.Networking
/// <param name="port">Port to listen for clients on.</param> /// <param name="port">Port to listen for clients on.</param>
public void Listen(ushort port) public void Listen(ushort port)
{ {
if (PacketTypes.Count == 0) throw new Exception("No packet types added");
this.Port = port; this.Port = port;
try try
{ {
if (!Listening) if (!Listening)
{ {
lock (_clientsLock)
{
_clients = new List<Client>();
}
_item = new SocketAsyncEventArgs();
_item.Completed += AcceptClient;
if (_handle != null) if (_handle != null)
{ {
_handle.Close(); _handle.Close();
_handle = null;
} }
if (BufferManager == null)
BufferManager = new PooledBufferManager(BUFFER_SIZE, 1) { ClearOnReturn = true };
_handle = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); _handle = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_handle.Bind(new IPEndPoint(IPAddress.Any, port)); _handle.Bind(new IPEndPoint(IPAddress.Any, port));
_handle.Listen(1000); _handle.Listen(1000);
@ -268,6 +261,15 @@ namespace xServer.Core.Networking
OnServerState(true); OnServerState(true);
if (_item != null)
{
_item.Dispose();
_item = null;
}
_item = new SocketAsyncEventArgs();
_item.Completed += AcceptClient;
if (!_handle.AcceptAsync(_item)) if (!_handle.AcceptAsync(_item))
AcceptClient(null, _item); AcceptClient(null, _item);
} }
@ -294,17 +296,7 @@ namespace xServer.Core.Networking
} }
/// <summary> /// <summary>
/// Adds Types to the serializer. /// Processes and accepts an incoming client.
/// </summary>
/// <param name="types">Types to add.</param>
public void AddTypesToSerializer(Type[] types)
{
PacketTypes.AddRange(types.Where(t => t != null));
}
/// <summary>
/// Processes an incoming client; adding the client to the list of clients,
/// hooking up the client's events, and finally accepts the client.
/// </summary> /// </summary>
/// <param name="s">Unused, use null.</param> /// <param name="s">Unused, use null.</param>
/// <param name="e">Asynchronously Socket Event</param> /// <param name="e">Asynchronously Socket Event</param>
@ -320,10 +312,8 @@ namespace xServer.Core.Networking
if (BufferManager.BuffersAvailable == 0) if (BufferManager.BuffersAvailable == 0)
BufferManager.IncreaseBufferCount(1); BufferManager.IncreaseBufferCount(1);
Client client = new Client(this, e.AcceptSocket, PacketTypes.ToArray()); Client client = new Client(this, e.AcceptSocket /*, PacketTypes.ToArray()*/);
client.ClientState += OnClientState; AddClient(client);
client.ClientRead += OnClientRead;
client.ClientWrite += OnClientWrite;
OnClientState(client, true); OnClientState(client, true);
break; break;
case SocketError.ConnectionReset: case SocketError.ConnectionReset:
@ -345,45 +335,36 @@ namespace xServer.Core.Networking
} }
/// <summary> /// <summary>
/// Adds a connected client to the list of clients. /// Adds a connected client to the list of clients,
/// subscribes to the client's events.
/// </summary> /// </summary>
/// <param name="client">The client to add.</param> /// <param name="client">The client to add.</param>
public void AddClient(Client client) private void AddClient(Client client)
{ {
lock (_clientsLock) lock (_clientsLock)
{ {
client.ClientState += OnClientState;
client.ClientRead += OnClientRead;
client.ClientWrite += OnClientWrite;
_clients.Add(client); _clients.Add(client);
} }
} }
/// <summary> /// <summary>
/// Removes a disconnected client from the list of clients. /// Removes a disconnected client from the list of clients,
/// unsubscribes from the client's events.
/// </summary> /// </summary>
/// <param name="client">The client to remove.</param> /// <param name="client">The client to remove.</param>
public void RemoveClient(Client client) private void RemoveClient(Client client)
{ {
if (_processing) return; if (_processing) return;
lock (_clientsLock) lock (_clientsLock)
{ {
int index = -1; client.ClientState -= OnClientState;
for (int i = 0; i < _clients.Count; i++) client.ClientRead -= OnClientRead;
if (_clients[i].Equals(client)) client.ClientWrite -= OnClientWrite;
{ _clients.Remove(client);
index = i;
break;
}
if (index < 0)
return;
try
{
_clients.RemoveAt(index);
}
catch
{
}
} }
} }
@ -402,20 +383,26 @@ namespace xServer.Core.Networking
_handle = null; _handle = null;
} }
if (_item != null)
{
_item.Dispose();
_item = null;
}
lock (_clientsLock) lock (_clientsLock)
{ {
if (_clients != null) while (_clients.Count != 0)
{ {
while (_clients.Count != 0) try
{
_clients[0].Disconnect();
_clients[0].ClientState -= OnClientState;
_clients[0].ClientRead -= OnClientRead;
_clients[0].ClientWrite -= OnClientWrite;
_clients.RemoveAt(0);
}
catch
{ {
try
{
_clients[0].Disconnect();
_clients.RemoveAt(0);
}
catch
{
}
} }
} }
} }

View File

@ -1,5 +1,7 @@
using System; using System;
using System.Linq;
using xServer.Core.Commands; using xServer.Core.Commands;
using xServer.Core.NetSerializer;
using xServer.Core.Packets; using xServer.Core.Packets;
namespace xServer.Core.Networking namespace xServer.Core.Networking
@ -9,7 +11,12 @@ namespace xServer.Core.Networking
/// <summary> /// <summary>
/// The amount of currently connected and authenticated clients. /// The amount of currently connected and authenticated clients.
/// </summary> /// </summary>
public int ConnectedClients { get; private set; } public int ConnectedClients {
get
{
return Clients.Count(c => c != null && c.Authenticated);
}
}
/// <summary> /// <summary>
/// Occurs when a client connected. /// Occurs when a client connected.
@ -62,9 +69,9 @@ namespace xServer.Core.Networking
/// <summary> /// <summary>
/// Constructor, initializes required objects and subscribes to events of the server. /// Constructor, initializes required objects and subscribes to events of the server.
/// </summary> /// </summary>
public ServerHandler() public ServerHandler() : base()
{ {
base.AddTypesToSerializer(new Type[] base.Serializer = new Serializer(new Type[]
{ {
typeof (Packets.ServerPackets.GetAuthentication), typeof (Packets.ServerPackets.GetAuthentication),
typeof (Packets.ServerPackets.DoClientDisconnect), typeof (Packets.ServerPackets.DoClientDisconnect),
@ -139,7 +146,6 @@ namespace xServer.Core.Networking
case false: case false:
if (client.Authenticated) if (client.Authenticated)
{ {
ConnectedClients--;
OnClientDisconnected(client); OnClientDisconnected(client);
} }
break; break;
@ -161,7 +167,6 @@ namespace xServer.Core.Networking
if (type == typeof (Packets.ClientPackets.GetAuthenticationResponse)) if (type == typeof (Packets.ClientPackets.GetAuthenticationResponse))
{ {
client.Authenticated = true; client.Authenticated = true;
ConnectedClients++;
new Packets.ServerPackets.SetAuthenticationSuccess().Execute(client); // finish handshake new Packets.ServerPackets.SetAuthenticationSuccess().Execute(client); // finish handshake
CommandHandler.HandleGetAuthenticationResponse(client, CommandHandler.HandleGetAuthenticationResponse(client,
(Packets.ClientPackets.GetAuthenticationResponse) packet); (Packets.ClientPackets.GetAuthenticationResponse) packet);

View File

@ -104,7 +104,10 @@ namespace xServer.Core.ReverseProxy
public void Stop() public void Stop()
{ {
if (_socket != null) if (_socket != null)
{
_socket.Close(); _socket.Close();
_socket = null;
}
lock (_clients) lock (_clients)
{ {

View File

@ -215,7 +215,7 @@ namespace xServer.Forms
lock (_lockClients) lock (_lockClients)
{ {
foreach (ListViewItem lvi in lstClients.Items.Cast<ListViewItem>() foreach (ListViewItem lvi in lstClients.Items.Cast<ListViewItem>()
.Where(lvi => lvi != null && (lvi.Tag as Client) != null && c.Equals((Client) lvi.Tag))) .Where(lvi => lvi != null && c.Equals(lvi.Tag)))
{ {
lvi.Remove(); lvi.Remove();
break; break;
@ -286,7 +286,7 @@ namespace xServer.Forms
lstClients.Invoke((MethodInvoker) delegate lstClients.Invoke((MethodInvoker) delegate
{ {
itemClient = lstClients.Items.Cast<ListViewItem>() itemClient = lstClients.Items.Cast<ListViewItem>()
.FirstOrDefault(lvi => lvi != null && lvi.Tag is Client && c.Equals((Client)lvi.Tag)); .FirstOrDefault(lvi => lvi != null && c.Equals(lvi.Tag));
}); });
return itemClient; return itemClient;