Files
Quasar/Server/Core/Server.cs
T
yankejustin b927aae0f8 Make sure to dispose of old Socket
Made sure the server disposed of the Socket when Server.Listen(ushort)
is called if the Socket was created before (called Server.Listen(ushort)
previously but stopped listening).
2015-04-07 12:27:56 -04:00

217 lines
5.8 KiB
C#

using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using xServer.Core.Packets;
namespace xServer.Core
{
public class Server
{
public long BytesReceived { get; set; }
public long BytesSent { get; set; }
public event ServerStateEventHandler ServerState;
public delegate void ServerStateEventHandler(Server s, bool listening);
private void OnServerState(bool listening)
{
if (ServerState != null)
{
ServerState(this, listening);
}
}
public event ClientStateEventHandler ClientState;
public delegate void ClientStateEventHandler(Server s, Client c, bool connected);
private void OnClientState(Client c, bool connected)
{
if (ClientState != null)
{
ClientState(this, c, connected);
}
}
public event ClientReadEventHandler ClientRead;
public delegate void ClientReadEventHandler(Server s, Client c, IPacket packet);
private void OnClientRead(Client c, IPacket packet)
{
if (ClientRead != null)
{
ClientRead(this, c, packet);
}
}
public event ClientWriteEventHandler ClientWrite;
public delegate void ClientWriteEventHandler(Server s, Client c, IPacket packet, long length);
private void OnClientWrite(Client c, IPacket packet, long length, byte[] rawData)
{
if (ClientWrite != null)
{
ClientWrite(this, c, packet, length);
}
}
private Socket _handle;
private SocketAsyncEventArgs _item;
private bool Processing { get; set; }
public bool Listening { get; private set; }
private List<Client> _clients;
public Client[] Clients
{
get
{
return Listening ? _clients.ToArray() : new Client[0];
}
}
public int ConnectedClients { get; set; }
public Dictionary<string, DateTime> AllTimeConnectedClients { get; set; }
private List<Type> PacketTypes { get; set; }
public Server()
{
PacketTypes = new List<Type>();
AllTimeConnectedClients = new Dictionary<string, DateTime>();
}
public void Listen(ushort port)
{
try
{
if (!Listening)
{
_clients = new List<Client>();
_item = new SocketAsyncEventArgs();
_item.Completed += Process;
if (_handle != null)
{
try
{
_handle.Close();
}
catch
{ }
}
_handle = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_handle.Bind(new IPEndPoint(IPAddress.Any, port));
_handle.Listen(1000);
Processing = false;
Listening = true;
OnServerState(true);
if (!_handle.AcceptAsync(_item))
Process(null, _item);
}
}
catch (Exception)
{
Disconnect();
}
}
/// <summary>
/// Adds a Type to the serializer so a message can be properly serialized.
/// </summary>
/// <param name="parent">The parent type, i.e.: IPacket</param>
/// <param name="type">Type to be added</param>
public void AddTypeToSerializer(Type parent, Type type)
{
if (type == null || parent == null)
throw new ArgumentNullException();
PacketTypes.Add(type);
}
public void AddTypesToSerializer(Type parent, params Type[] types)
{
foreach (Type type in types)
AddTypeToSerializer(parent, type);
}
private void Process(object s, SocketAsyncEventArgs e)
{
try
{
if (e.SocketError == SocketError.Success)
{
Client T = new Client(this, e.AcceptSocket, PacketTypes.ToArray());
lock (_clients)
{
_clients.Add(T);
T.ClientState += HandleState;
T.ClientRead += OnClientRead;
T.ClientWrite += OnClientWrite;
OnClientState(T, true);
}
e.AcceptSocket = null;
if (!_handle.AcceptAsync(e))
Process(null, e);
}
else
Disconnect();
}
catch
{
Disconnect();
}
}
public void Disconnect()
{
if (Processing)
return;
Processing = true;
if (_handle != null)
_handle.Close();
lock (_clients)
{
while (_clients.Count != 0)
{
_clients[0].Disconnect();
try
{
_clients.RemoveAt(0);
}
catch
{ }
}
}
Listening = false;
OnServerState(false);
}
private void HandleState(Client s, bool open)
{
lock (_clients)
{
_clients.Remove(s);
OnClientState(s, false);
s.Value.DisposeForms();
}
}
}
}