This is just a very basic source that I have been working on. Looking for some suggestions, so thought that I would throw it up here for some feedback. My main focus has been on the SQL system and making the query times very quick and cost efficient. Mainly looking for ideas in regards to threading. I know using too many threads is very inefficient, yet I don't like constantly checking timestamps on buffs to see if they need to be removed. Any ideas or suggestions would be greatly appreciated.
Credits:
Infamous and CptSky for Cryptography/Socket System
well, i just checked it using notepad since i don't have my laptop rigth now(hard to look in details without an IDE :c) but the first thing i saw was that you are creating an infinite loop in a thread from the ThreadPool, try to avoid this since that pool is supposed to be used by other .net applications too, not that -1 thread could cause a big impact, but it's a bad practice.
you are also using a thread-safe wrapper for the Dictionary class, when u could use a ConcurrentDictionary, i haven't tested yet but i suppose that ConcurrentDictionary only need to 'lock' when a remove or a loop is being executed, while the wrapper of the dictionary needs to lock when you are adding a pair too.
I saw that u are using a Stopwatch to do some checks, it's something i have thougth a lot too since DateTime lacks of precision, have not found anything against it
I kinda dislike too(just personal opinion)the way that u have splitted the packets in ToReceive and ToSend when could have only one class with the methods needed, it looks a bit disorganized(if exists that word O.o), for example this is how I LIKE, emphasis in the I xd to have the packets
Code:
class AuthorizationResponse : IServerPacket
{
private static readonly NetPacketHeader Header = new NetPacketHeader()
{
Length = 32,
ID = 1055
};
public uint UID;
public AccountPermission Authorization;
public string MsgServerIP = "SERVER_IP";//configuration
public int MsgServerPort = SERVER_PORT;//configuration
public NetPacket Serialize()
{
NetPacket packet = new NetPacket(Header, false);
packet.WriteUInt32(UID);
packet.WriteUInt32((uint)Authorization);
packet.WriteString(MsgServerIP, 16);
packet.WriteInt32(MsgServerPort);
return packet;
}
}
IServerPacket is an interface that make the packet's class have a Serialize method, or what is your ToSend folder, or something like that xd.
i also have an interface called IClientPacket, that will be the ToReceive folder idea too, with the methods Deserialize and Process like this
Code:
public class AuthorizationRequest : IClientPacket
{
public string Account;
public string Password;
public string ServerName;
public void Deserialize(NetPacket packet)
{
packet.Seek(4, SeekOrigin.Begin);
Account = packet.ReadString(16).TrimEnd('\0', ' ');
Password = packet.ReadString(16).TrimEnd('\0', ' ');
ServerName = packet.ReadString(16).TrimEnd('\0', ' ');
packet.Dispose();
}
public void Process(object sender)
{
AuthClient client = sender as AuthClient;
IServerPacket response = new AuthorizationResponse();
try
{
using (MySqlReader reader = new MySqlReader())
{
reader.Select("accounts");
reader.WhereMatch("account", Account);
reader.Execute();
string realPassword = PasswordCryptography.EncryptPassword(reader.ReadString("password"));
client.UID = reader.ReadUInt32("uid");
response.UID = client.UID;
if (LoginExploits.AccountClients.ContainsKey(response.UID))
client.Disconnect();
AccountPermission permission = (AccountPermission)reader.ReadByte("state");
switch (permission)
{
case AccountPermission.Moderator:
case AccountPermission.ProjectManager:
case AccountPermission.Normal:
response.Authorization = AccountPermission.Normal;
break;
case AccountPermission.Banned:
case AccountPermission.Unactivated:
response.Authorization = permission;
break;
default:
response.Authorization = AccountPermission.Error;
break;
}
if (response.Authorization == AccountPermission.Normal)
{
if(realPassword != Password)
response.Authorization = AccountPermission.Invalid;
}
LoginExploits.AccountClients.Add(client.UID, client);
}
}
catch(Exception e)
{
Console.WriteLine(e);
response.Authorization = AccountPermission.Invalid;
}
client.Send(response);
}
}
maybe not the best code, but an example of the 'concept' behind how i structure my packets.
hope helped a little bit
I have actually tested the concurrent dictionary, and it's actually a bit slower then the method im using. Im not sure, but I believe its meant for much larger scaling, and will scale better, but isnt really useful in anything related to co servers. Thanks for the advice tho, will be looking into the thread situation and see which one will fit it best. You happen to know if a new thread, task/threading.timer, or Timers.timer would be better?
Any collection under System.Collections.Concurrent is designed to handle thread-safety up to a much larger scale yours probably will and I believe it will be faster when you start to use multiple threads that's accessing the same objects within the collection. That's because the collections does not use a global lock for itself, but a lock for each entry.
Ex. This is the TryAdd method for ConcurrentDictionary.
Code:
[__DynamicallyInvokable]
public bool TryAdd(TKey key, TValue value)
{
if (key == null)
{
throw new ArgumentNullException("key");
}
TValue tValue;
return this.TryAddInternal(key, value, false, true, out tValue);
}
Code:
private bool TryAddInternal(TKey key, TValue value, bool updateIfExists, bool acquireLock, out TValue resultingValue)
{
int hashCode = this.m_comparer.GetHashCode(key);
checked
{
ConcurrentDictionary<TKey, TValue>.Tables tables;
bool flag;
while (true)
{
tables = this.m_tables;
int num;
int num2;
this.GetBucketAndLockNo(hashCode, out num, out num2, tables.m_buckets.Length, tables.m_locks.Length);
flag = false;
bool flag2 = false;
try
{
if (acquireLock)
{
Monitor.Enter(tables.m_locks[num2], ref flag2);
}
if (tables != this.m_tables)
{
continue;
}
ConcurrentDictionary<TKey, TValue>.Node node = null;
for (ConcurrentDictionary<TKey, TValue>.Node node2 = tables.m_buckets[num]; node2 != null; node2 = node2.m_next)
{
if (this.m_comparer.Equals(node2.m_key, key))
{
if (updateIfExists)
{
if (ConcurrentDictionary<TKey, TValue>.s_isValueWriteAtomic)
{
node2.m_value = value;
}
else
{
ConcurrentDictionary<TKey, TValue>.Node node3 = new ConcurrentDictionary<TKey, TValue>.Node(node2.m_key, value, hashCode, node2.m_next);
if (node == null)
{
tables.m_buckets[num] = node3;
}
else
{
node.m_next = node3;
}
}
resultingValue = value;
}
else
{
resultingValue = node2.m_value;
}
return false;
}
node = node2;
}
Volatile.Write<ConcurrentDictionary<TKey, TValue>.Node>(ref tables.m_buckets[num], new ConcurrentDictionary<TKey, TValue>.Node(key, value, hashCode, tables.m_buckets[num]));
tables.m_countPerLock[num2]++;
if (tables.m_countPerLock[num2] > this.m_budget)
{
flag = true;
}
}
finally
{
if (flag2)
{
Monitor.Exit(tables.m_locks[num2]);
}
}
break;
}
if (flag)
{
this.GrowTable(tables);
}
resultingValue = value;
return true;
}
}
Yeah, another thing i didn't like about it was the fact you always had to have an out parameter when your removing an item from the dictionary. Just annoying hah.
case "newacct":
{
Database.Methods.NewAccount(Command[1], Command[2]);
break;
}
default: break;
"default: break;" isn't needed
Infact - Have you tried using reSharper? It really cleans things up.
Behold! Entry.cs with resharped!
PHP Code:
using System; using System.Text; using GameCore; using GameCore.Enums; using GameCore.Network; namespace AuthServer { public sealed class Entry { public static ThreadSafeRandom Random = new ThreadSafeRandom(); private static void Main() { Console.Title = "Auth Server"; var authSocket = new NetworkSocket(); authSocket.OnDisconnect += AnnounceDisconnection; authSocket.OnReceive += AnnounceReceive; authSocket.OnConnect += AnnounceConnect; authSocket.Listen(9958); authSocket.Accept();
Console.WriteLine("Listening for New Connections...");
case "newacct":
{
Database.Methods.NewAccount(Command[1], Command[2]);
break;
}
default: break;
"default: break;" isn't needed
Some IDE might request a default case in switches (at least, in C++). It's a good practice to have a default case. (And if it shouldn't go inside, to put an assert).
case "newacct":
{
Database.Methods.NewAccount(Command[1], Command[2]);
break;
}
default: break;
"default: break;" isn't needed
Some IDE might request a default case in switches (at least, in C++). It's a good practice to have a default case. (And if it shouldn't go inside, to put an assert).
I don't know any C# IDE's that requires it and the C# compiler for sure doesn't. However it's common in other languages as you already said ex. C++, D and such ... Not necessary in C# at least not with any of the popular IDE's Visual Studio, Mono and #Develop.
A 64 bit computer is able to run 32 bit and 64 bit programs, however a 32 bit computer can only run a 32 bit program.
So if you are trying to run a program on a 64 bit computer and get an error, the problem should not be that.
Actually it could be that some of the DLL files used in PInvoke are 64 bit such as msvcrt.dll but the program is 32bit, so when it tries to PInvoke it will throw an exception
[Release] Extremely basic (but working/bugless) C# Source 11/30/2012 - CO2 PServer Guides & Releases - 348 Replies This pretty much has a very finite amount of stuff done in it. Specifically this is pretty much all thats in it.
If your serious about trying to develop a server in C#, I suggest looking at this. There's a DLL also included (check the "bin" folder) which will need to be added as a reference. SocketNetwork.dll pretty much handles the socket-system and encryptions for you it is not packed or obfuscated if you would like to decompile it and take a look at it, be my guest.
I included a folder...