私が取り組んでいるゲーム用の汎用ソケット サーバーを作成しようとしています。SmartFox や Photon などの既に構築されたサーバーを十分に使用できることはわかっていますが、学習目的で自分でサーバーを作成するという苦労はしたくありません。
基本的なデータ型、その配列、および特別な GSObject をバイナリに変換し、それらをクライアント エンドでオブジェクト形式に戻すことができるように配置する、BSON にインスパイアされたプロトコルを考え出しました。コアでは、変換メソッドは .Net BitConverter クラスを利用して、基本的なデータ型をバイナリに変換します。とにかく、問題はパフォーマンスです。50,000 回ループし、約 5500 ミリ秒かかるたびに GSObject をバイナリに変換するとします (結果の byte[] は変換ごとにわずか 192 バイトです)。これは、1000 人の同時ユーザーで毎秒 5 ~ 10 の位置更新を送信する MMO には遅すぎると思います。はい、1 つのゲームで同時に 1000 人のユーザーが参加する可能性は低いことは承知していますが、前述したように、これは私にとって学習プロセスであるはずです。
そうです、誰かが他の変換テクニックを知っていたり、私がどこでパフォーマンスを落としているかを見たりしたら、助けていただければ幸いです。
GSBitConverter.cs
これはメインの変換クラスです。メインのデータ型に拡張メソッドを追加して、バイナリ形式に変換します。BitConverter クラスを使用して基本型を変換します。整数と整数配列を変換するコードのみを示しましたが、残りのメソッドはこれら 2 つのほとんどのレプリカであり、型をオーバーロードしているだけです。
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");
}
上記のコードで使用されている他のいくつかのクラスのコードを次に示します。そのほとんどは繰り返しです。