الشبكات في UNET Low Level API الدرس الثاني

في الدرس السابق قمنا بالاتصال فاصبح لدينا server و clients وفي هذا الدرس سوف تكمل المسيرة لنرى كيف نتشارك المعلومات بين ال server وال clients .

استقبال الرسائل

طريقة الاستقبال جميعهم متشابهين نفس الأسطر وهي على الشكل التالي

//in clients
client.RegisterHandler(msgType,NetworkMessageDelegate)

//in server
NetworkServer.RegisterHandler(msgType,NetworkMessageDelegate)

msgType هي من النوع short اي رقم من 16 بت من -32,768 الى 32,767 بعض هذه الارقام محجوزة مسبقا لا ستقبال بعض رسائل الشبكة مثل connect,ready,addPlayer .. الخ وتجدها كلها في MsgType .
NetworkMessageDelegate وهو callback عند استقبال رسالة ال msgType  نفس الرقم الذي تم تسجيلة يتم استدعاءه تلقائيا وله parameter وحيد من النوع NetworkMessage .

ارسال الرسائل

ليس هناك اختلاف كبير بين ان ترسل من ال srever الى ال clients او العكس سوى ان ال clients يرسل للسيرفر فقط و السيرفر يرسل لكل ال clients او الclient محدد او ال clients الذين في حالة ready لذلك في السيرفر تكون هناك خيارات اكبر في الارسال .
وابسط طريقة للارسال هي استخدام الامر Send

//in clients
client.Send(msgType,message)

//in server
NetworkServer.SendToAll(msgType,message)
NetworkServer.SendToClient(client,msgType,message)
NetworkServer.SendToReady(msgType,message)

الامر send بجميع اشكاله يرسل عبر reliable channel افتراضيا مالم تغير في اعدادت ال channels وهي ان تضمن وصول الرسالة للاعب او السيرفر .
msgType تعرفنا اليه مسبقا
message وهو يجب ان يكون من كلاسس يرث من MessageBase وبشكله البسيط

public class MyMessage : MessageBase
{
    public string comment;
}

اما اذا اردت تخصيص اكثر

public class MyMessage : MessageBase
{
    public string comment;
    public override void Deserialize(NetworkReader reader)
    {
        comment = reader.ReadString();
    }

    // This method would be generated
    public override void Serialize(NetworkWriter writer)
    {
        writer.Write(comment);
    }
}

مثال ارسال من السيرفر الى كل اللاعبين

NetworkServer.SendToAll(99, new MyMessage() { comment = "hello" });

في المقابل حتى يستقبل جميع اللاعبين الرسائل

client.RegisterHandler(99, (NetworkMessage message) => { 
     print(message.ReadMessage<MyMessage>().comment); 
});

الطريقة الاخرى لانشاء رسالة دون الحاجة للوراثة من messageBase هي

NetworkWriter writer = new NetworkWriter();
writer.StartMessage(99);
writer.Write("ana mohammed");
writer.FinishMessage();
cline.SendWriter(writer,0);

ويمكن استقبال من ال server على انها message من النوع myMessage او NetworkReader

NetworkServer.RegisterHandler(50, (NetworkMessage message) => {
     print(message.ReadMessage<MyMessage>().comment);
     or
     print(message.reader.ReadString());
});

الرقم في البارامتر الثاني في SendWriter هو رقم ال Channels وافتراضيا ان لم تغير في الاعدادات الاتصال يرمز ل Channels.DefaultReliable .

Channels

بامكانك عند ارسال الرسالة ان تخصص الرسالة ل channel وهذا ال channel يحدد طريقة ارسال الرسالة حسب نوعه (جميع الانواع تجدها في QosType )

Unreliable	There is no guarantee of delivery or ordering.

UnreliableFragmented	There is no guarantee of delivery or ordering, but allowing fragmented messages with up to 32 fragments per message.

UnreliableSequenced	There is no guarantee of delivery and all unordered messages will be dropped. Example: VoIP.

Reliable	Each message is guaranteed to be delivered but not guaranteed to be in order.

ReliableFragmented	Each message is guaranteed to be delivered, also allowing fragmented messages with up to 32 fragments per message.

ReliableSequenced	Each message is guaranteed to be delivered and in order.

StateUpdate	An unreliable message. Only the last message in the send buffer is sent. Only the most recent message in the receive buffer will be delivered.

ReliableStateUpdate	A reliable message. Note: Only the last message in the send buffer is sent. Only the most recent message in the receive buffer will be delivered.

AllCostDelivery	A reliable message that will be re-sent with a high frequency until it is acknowledged.

افتراضيا في حال لم تغير في اعدادت الاتصال يتوفر قناتين للارسال (two channels)  القناة رقم 0 ونوعها reliable channel  والقناة رقم 1 ونوعها unreliable channel  القناتين هم (Channels.DefaultReliable  و Channels.DefaultUnreliable)

// in server
NetworkServer.SendByChannelToAll(99, new MyMessage() { comment = "hello" },0);
Or
NetworkServer.SendByChannelToAll(99, new MyMessage() { comment = "hello" },Channels.DefaultReliable);
//in client
client.RegisterHandler(99, (NetworkMessage message) => {
     print(message.ReadMessage<MyMessage>().comment);
     print(message.channelId);
});

اضافة وحذف channels للاتصال يكون من خلال ConnectionConfig وتضاف الى NetworkServer و NetworkClient وتكون قبل listen و connect

ConnectionConfig config = new ConnectionConfig();
config.AddChannel(QosType.Reliable);//0
config.AddChannel(QosType.Unreliable);//1
config.AddChannel(QosType.ReliableSequenced);//2
config.AddChannel(QosType.UnreliableSequenced);//4
NetworkServer.Configure(config,100);

وبنفس الطريقة ايضا يتم اضافتها لل client و هناك اعدادات اخرى يمكن اضافتها لل channel ولكن لكل اتصال بالطريقة هذه

client.connection.SetChannelOption(0, ChannelOption.MaxPendingBuffers, 16);//عددالرسائل في البفر معلقة بسبب فشل ارسالها الى طبقة النقل transport layer

بالاضافة الى مجموع خيارات تجدها في ChannelOption . في المثال السابق اضفنا الخيار للاتصال من ال client الى ال server ويمكن ايضا فعل العكس  .
قبل بدء عمل السيرفر او حتى الاتصال بالسيرفر يمكن اضافة مجموعة اعدادات لطبقة النقل transport layer وبعض هذه الاعدادت يجب ان تطابق في ال clients و ال server مثال للاعدادات

//in client
ConnectionConfig config = new ConnectionConfig();
config.AddChannel(QosType.Reliable);
config.AddChannel(QosType.Unreliable);
config.AddChannel(QosType.ReliableSequenced);
config.AddChannel(QosType.UnreliableSequenced);
config.SendDelay = 1000;//تنتظر ثانية قبل ارسال البيانات خلال هذه الثانية يمكنها جمع بيانات اكثر
config.DisconnectTimeout = 10000;// ينتظر عشر ثوان على طلب فصل الاتصال او في حال لم يتلقى او يرسل اي حزمة في 10 ثوان او في حال 
client.Configure(config,100);
client.Connect("127.0.0.1", 4444);

//in server
ConnectionConfig config = new ConnectionConfig();
config.AddChannel(QosType.Reliable);
config.AddChannel(QosType.Unreliable);
config.AddChannel(QosType.ReliableSequenced);
config.AddChannel(QosType.UnreliableSequenced);
config.DisconnectTimeout = 10000;
NetworkServer.Configure(config, 100);

ولمشاهدة المزيد من الاعدادات راجع ConnectionConfig
والى هنا تنتهي مواضيع ال low level وسوف نكمل مع ال high level .