Я пытаюсь написать сервер сокетов общего назначения для игры, над которой я работаю. Я знаю, что могу очень хорошо использовать уже построенные серверы, такие как SmartFox и Photon, но я не хочу испытывать трудности, связанные с его созданием в учебных целях.
Я придумал протокол, основанный на BSON, для преобразования основных типов данных, их массивов и специального GSObject в двоичный файл и упорядочения их таким образом, чтобы их можно было собрать обратно в форму объекта на клиенте конец. По сути, методы преобразования используют класс .Net BitConverter для преобразования основных типов данных в двоичные. В любом случае, проблема заключается в производительности, если я зациклюсь 50000 раз и преобразую свой GSObject в двоичный файл каждый раз, когда для этого требуется около 5500 мс (результирующий байт [] составляет всего 192 байта на преобразование). Я думаю, что это будет слишком медленно для MMO, который отправляет 5-10 обновлений позиции в секунду с 1000 одновременно работающих пользователей. Да, я знаю, что маловероятно, что в игре одновременно будет 1000 пользователей, но, как я уже говорил ранее, это должно быть процессом обучения для меня, я хочу пойти дальше и создать что-то, что хорошо масштабируется и может обслуживать не менее нескольких тысяч пользователей.
Так что, если кто-то знает о других методах преобразования или видит, где я теряю производительность, я был бы признателен за помощь.
GSBitConverter.cs
Это основной класс преобразования, он добавляет методы расширения к основным типам данных для преобразования в двоичный формат. Он использует класс BitConverter для преобразования базовых типов. Я показал только код для преобразования целочисленных и целочисленных массивов, но остальная часть метода в значительной степени является копией этих двух, они просто перегружают тип.
public static class GSBitConverter
{
public static byte[] ToGSBinary(this short value)
{
return BitConverter.GetBytes(value);
}
public static byte[] ToGSBinary(this IEnumerable<short> value)
{
List<byte> bytes = new List<byte>();
short length = (short)value.Count();
bytes.AddRange(length.ToGSBinary());
for (int i = 0; i < length; i++)
bytes.AddRange(value.ElementAt(i).ToGSBinary());
return bytes.ToArray();
}
public static byte[] ToGSBinary(this bool value);
public static byte[] ToGSBinary(this IEnumerable<bool> value);
public static byte[] ToGSBinary(this IEnumerable<byte> value);
public static byte[] ToGSBinary(this int value);
public static byte[] ToGSBinary(this IEnumerable<int> value);
public static byte[] ToGSBinary(this long value);
public static byte[] ToGSBinary(this IEnumerable<long> value);
public static byte[] ToGSBinary(this float value);
public static byte[] ToGSBinary(this IEnumerable<float> value);
public static byte[] ToGSBinary(this double value);
public static byte[] ToGSBinary(this IEnumerable<double> value);
public static byte[] ToGSBinary(this string value);
public static byte[] ToGSBinary(this IEnumerable<string> value);
public static string GetHexDump(this IEnumerable<byte> value);
}
Program.cs
Вот объект, который я преобразовываю в двоичный файл в цикле.
class Program
{
static void Main(string[] args)
{
GSObject obj = new GSObject();
obj.AttachShort("smallInt", 15);
obj.AttachInt("medInt", 120700);
obj.AttachLong("bigInt", 10900800700);
obj.AttachDouble("doubleVal", Math.PI);
obj.AttachStringArray("muppetNames", new string[] { "Kermit", "Fozzy", "Piggy", "Animal", "Gonzo" });
GSObject apple = new GSObject();
apple.AttachString("name", "Apple");
apple.AttachString("color", "red");
apple.AttachBool("inStock", true);
apple.AttachFloat("price", (float)1.5);
GSObject lemon = new GSObject();
apple.AttachString("name", "Lemon");
apple.AttachString("color", "yellow");
apple.AttachBool("inStock", false);
apple.AttachFloat("price", (float)0.8);
GSObject apricoat = new GSObject();
apple.AttachString("name", "Apricoat");
apple.AttachString("color", "orange");
apple.AttachBool("inStock", true);
apple.AttachFloat("price", (float)1.9);
GSObject kiwi = new GSObject();
apple.AttachString("name", "Kiwi");
apple.AttachString("color", "green");
apple.AttachBool("inStock", true);
apple.AttachFloat("price", (float)2.3);
GSArray fruits = new GSArray();
fruits.AddGSObject(apple);
fruits.AddGSObject(lemon);
fruits.AddGSObject(apricoat);
fruits.AddGSObject(kiwi);
obj.AttachGSArray("fruits", fruits);
Stopwatch w1 = Stopwatch.StartNew();
for (int i = 0; i < 50000; i++)
{
byte[] b = obj.ToGSBinary();
}
w1.Stop();
Console.WriteLine(BitConverter.IsLittleEndian ? "Little Endian" : "Big Endian");
Console.WriteLine(w1.ElapsedMilliseconds + "ms");
}
Вот код для некоторых других моих классов, которые используются в коде выше. Большая часть повторяется.
GSObject
GSArray
GSWrappedObject