مكتبة شبكة عالية الأداء وسهلة الاستخدام تدعم أكثر من 16 ألف عميل متزامن على جميع الطبولوجيا المتوفرة.
مصمم للتطبيقات المتزامنة الموزعة في الوقت الفعلي عبر الشبكة المحلية (LAN) أو الإنترنت.
يوفر بنية تحتية لتمرير الرسائل عالية الإنتاجية، وP2P، وNat Traversal، وUdp الموثوق.
يتكون هذا المستودع من التجميع الأساسي الرئيسي والعديد من التجميعات الفرعية الخاصة بالتسلسل.
يرجى مراجعة صفحة Wiki للحصول على وثائق مفصلة.
مكتبة الشبكة، تشمل كل المنطق المرتبط بأنظمة الشبكة، بدءًا من البايتات الأولية وحتى التجريدات مثل ردهات P2P. يوفر قوالب عامة لاستخدامها مع أي نوع من التسلسل.
نماذج التوصيل والتشغيل عالية الأداء، تعمل بالبايتات الأولية. تستخدم أيضًا كقاعدة للنماذج ذات المستوى الأعلى.
Tcp Server/Client model
مع التخزين المؤقت الديناميكي وأنظمة الانتظار الفرعية، يمكن أن تكون وحدات البايت مجزأة مثل المقابس العادية.Tcp Byte Message Server/Client
حيث يتم إرسال البايتات برأس يبلغ طوله 4 بايت. إنه يضمن تسليم الرسالة الذرية دون تجزئة.Udp Server/Client
نظام udp حيث تتم محاكاة الخادم مع تحسين الأداء.Reliable Udp Client/Server
حيث يتم تنفيذ بروتوكول TCP الحديث عبر Udp.يتضمن نماذج عامة يمكنها العمل مع أي بروتوكول تسلسل.
Generic Message Server/Client
مصمم لإرسال واستقبال الرسائل المتسلسلة بشكل ذري.Generic MessageProtocol Server/client
مشابه لما ورد أعلاه، ولكن مع إضافة فئة الناقل "MessageEnvelope"، المستخدمة كرأس/بيانات تعريف.P2P Relay Client/Server
حيث يكتشف الزملاء (العملاء) بعضهم البعض عبر خادم Relay، ويمكنهم استخدام Udp/Rudp/Tcp للتواصل. يدعم TCP & Udp Holepunch.P2P Room/Lobby Server/Client
لنموذج الترحيل حيث يمكن للأقران تحديد غرفة، على غرار خوادم التوفيق بين الألعاب.يتم اختبار المكتبة مع العديد من العملاء الذين يدعمهم نظام التشغيل (Windows) (حوالي 16 ألف منفذ ديناميكي). يتم اختبار موثوقية البيانات بما في ذلك RUDP عبر الإنترنت على نطاق واسع. تم أيضًا اختبار ثقب Nat Traversal Udp عبر الإنترنت بنجاح.
ملاحظة: يحتوي Libary على تعليمات برمجية غير آمنة وتخصيصات للذاكرة المكدسة. يتم اختبار الأقسام غير الآمنة جيدًا ولا تخضع للتغيير.
يتم تنفيذ النماذج العامة من التجميع الرئيسي باستخدام مُسلسل محدد. سبب هذا التقسيم هو تجنب التبعيات غير الضرورية. جميع توقيعات الطريقة والاستخدام متطابقة. ويشمل:
تتوفر حزم Nuget:
مكتبة الشبكة الأساسية | بروتوبوف | حزمة الرسائل | NetSeralizer | جسون |
---|---|---|---|---|
يتم إجراء معايير الصدى اللانهائي عن طريق إرسال مجموعة من الرسائل إلى الخادم والحصول على استجابة الصدى. كل استجابة تؤدي إلى طلب جديد. يتم احتساب كل استجابة من الخادم كصدى واحد.
1000 رسالة أولية (32 بايت رسالة + 4 رأس) لكل منها:
لاب توب ايه ام دي رايزن 7 5800H
عدد العملاء | صدى TCP في الثانية | صدى SSL في الثانية |
---|---|---|
100 | 53,400,000 | 41,600,000 |
1000 | 43,600,000 | 22,200,000 |
5000 | 43,400,000 | 21,800,000 |
10000 | 42,800,000 | 21,700,000 |
لاب توب انتل i9 13980HX
عدد العملاء | صدى TCP في الثانية | صدى SSL في الثانية |
---|---|---|
100 | 128,800,000 | 79,400,000 |
1000 | 110,400,000 | 72,100,000 |
5000 | 102,100,000 | 67,500,000 |
10000 | 100,500,000 | 65,500,000 |
1000 مغلف رسالة أولية (حمولة 32 بايت، إجمالي 48 بايت):
لاب توب ايه ام دي رايزن 7 5800H
عدد العملاء | بروتوبوف صدى في الثانية | تأمين صدى Protobuf في الثانية |
---|---|---|
100 | 9,440,000 | 8,050,000 |
1000 | 8,780,000 | 7,480,000 |
5000 | 8,360,000 | 7,390,000 |
10000 | 8,340,000 | 7,350,000 |
لاب توب انتل i9 13980HX
عدد العملاء | بروتوبوف صدى في الثانية | تأمين صدى Protobuf في الثانية |
---|---|---|
100 | 31,200,000 | 20,650,000 |
1000 | 30,500,000 | 19,500,000 |
5000 | 28,200,000 | 17,650,000 |
10000 | 26,400,000 | 16,000,000 |
تقوم هذه المعايير بإرسال مغلف رسالة فقط مع حمولة بايت أولية. للحصول على أداء محدد للتسلسل، يرجى الرجوع إلى: SerializationBenchmarks
للحصول على معلومات تفصيلية، راجع AsyncTcpClient/Server وByteMessageTcpClient/Server
أي قطعة من صفيف البايت أو قطعة الصفيف ستصل إلى الوجهة دون تجزئة.
private static void ExampleByteMessage ( )
{
ByteMessageTcpServer server = new ByteMessageTcpServer ( 20008 ) ;
server . OnBytesReceived += ServerBytesReceived ;
server . StartServer ( ) ;
ByteMessageTcpClient client = new ByteMessageTcpClient ( ) ;
client . OnBytesReceived += ClientBytesReceived ;
client . Connect ( "127.0.0.1" , 20008 ) ;
client . SendAsync ( Encoding . UTF8 . GetBytes ( "Hello I'm a client!" ) ) ;
void ServerBytesReceived ( Guid clientId , byte [ ] bytes , int offset , int count )
{
Console . WriteLine ( Encoding . UTF8 . GetString ( bytes , offset , count ) ) ;
server . SendBytesToClient ( clientId , Encoding . UTF8 . GetBytes ( "Hello I'm the server" ) ) ;
}
void ClientBytesReceived ( byte [ ] bytes , int offset , int count )
{
Console . WriteLine ( Encoding . UTF8 . GetString ( bytes , offset , count ) ) ;
}
}
output:
Hello I'm a client!
Hello I'm the server
ملاحظة: إعداد الأداء المهم هنا هو ما إذا كان سيتم استخدام مخزن مؤقت أو قائمة انتظار كسياسة تخزين مؤقت. استخدم Buffer إذا كانت الرسائل عبارة عن مناطق بايت [] بشكل أساسي مثل (buffer، offset،count). استخدم قائمة الانتظار إذا كانت الرسائل ممتلئة بالبايت[] (من 0 إلى النهاية).
client . GatherConfig = ScatterGatherConfig . UseQueue ;
server . GatherConfig = ScatterGatherConfig . UseBuffer ;
بالنسبة لمتغيرات SSL فإن الفرق هو:
var ccert = new X509Certificate2 ( "client.pfx" , "greenpass" ) ;
// null certificate or default constructor will generate self signed certificate
client = new SslByteMessageClient ( ccert ) ;
var scert = new X509Certificate2 ( "server.pfx" , "greenpass" ) ;
// null certificate or default constructor will generate self signed certificate
server = new SslByteMessageServer ( 8888 , scert ) ;
// You can override the SSL cerificate validation callback
server . RemoteCertificateValidationCallback += .. .
client . RemoteCertificateValidationCallback += .. .
لمزيد من المعلومات، راجع SSLClient/Server وSSLByteMessageClient/Server
الخادم/العميل الأساسي حيث يتم نقل البايتات الأولية. تتطابق توقيعات الأسلوب ورد الاتصال مع نماذج رسائل البايت. لا يوجد بروتوكول يتم تطبيقه على الخادم/العميل الأساسي، وبالتالي قد يتم تجزئة وحدات البايت وفقًا لحجم وحدة الإرسال الكبرى لديك.
AsyncTcpServer server = new AsyncTcpServer ( port : 20000 ) ;
AsyncTpcClient client = new AsyncTpcClient ( ) ;
// SSL variant
// null certificate or default constructor will generate self signed certificate
var ccert = new X509Certificate2 ( "client.pfx" , "greenpass" ) ;
var scert = new X509Certificate2 ( "server.pfx" , "greenpass" ) ;
SslServer server = new SslServer ( 2000 , scert ) ;
SslClient client = new SslClient ( ccert ) ;
الشبكات المتسلسلة هي تطبيقات للفئات العامة التي توفرها Core Library، وهي قابلة للتطبيق على جميع بروتوكولات التسلسل.
لمزيد من المعلومات: الشبكة التسلسلية
Examples here is only given for Protobuf-net, but signature is identical for any other provided serialization protocol(MessagePack, Json etc)
.
ينفذ نموذج عميل الخادم حيث يتم نقل الرسائل المتسلسلة ذريًا. أعلن عن نوعك:
[ ProtoContract ]
class SampleMessage
{
[ ProtoMember ( 1 ) ]
public string sample ;
}
PureProtoServer server = new PureProtoServer ( 11234 ) ;
server . StartServer ( ) ;
server . BytesReceived += ( clientId , bytes , offset , count ) =>
{
SampleMessage msg = server . Serializer . Deserialize < SampleMessage > ( bytes , offset , count ) ;
Console . WriteLine ( msg . sample ) ;
msg . sample = "Jesse Lets cook" ;
server . SendAsync ( clientId , msg ) ;
} ;
PureProtoClient client = new PureProtoClient ( ) ;
client . Connect ( "127.0.0.1" , 11234 ) ;
client . BytesReceived += ( bytes , offset , count ) =>
{
SampleMessage msg = client . Serializer . Deserialize < SampleMessage > ( bytes , offset , count ) ;
Console . WriteLine ( msg . sample ) ;
} ;
client . SendAsync ( new SampleMessage ( ) { sample = "Yo! Mr White" } ) ;
يتم تطبيق بروتوكول الرسائل لتغليف جميع أنواع الرسائل الديناميكية برأس قياسي. يرجى الرجوع إلى بروتوكول الرسائل للحصول على شرح مفصل.
يمكنك الإعلان عن أنواع الحمولة النافعة لديك، أي نوع قابل للتسلسل باستخدام protobuf.
[ ProtoContract ]
class SamplePayload : IProtoMessage
{
[ ProtoMember ( 1 ) ]
public string sample ;
}
مثال للمتغير الآمن:
private static async Task ExampleProtoSecure ( )
{
// null certificate or default constructor will generate self signed certificate
var scert = new X509Certificate2 ( "server.pfx" , "greenpass" ) ;
var cert = new X509Certificate2 ( "client.pfx" , "greenpass" ) ;
SecureProtoMessageServer server = new SecureProtoMessageServer ( 20008 , scert ) ;
server . StartServer ( ) ;
server . OnMessageReceived += ServerMessageReceived ;
var client = new SecureProtoMessageClient ( cert ) ;
client . OnMessageReceived += ClientMessageReceived ;
client . Connect ( "127.0.0.1" , 20008 ) ;
var Payload = new SamplePayload ( ) { sample = "Hello" } ;
var messageEnvelope = new MessageEnvelope ( ) ;
messageEnvelope . Header = "PayloadTest" ;
// You can just send a message, get replies on ClientMessageReceived.
client . SendAsyncMessage ( messageEnvelope ) ;
client . SendAsyncMessage ( messageEnvelope , Payload ) ;
// Or you can wait for a reply async.
MessageEnvelope result = await client . SendMessageAndWaitResponse ( messageEnvelope , Payload ) ;
var payload = result . UnpackPayload < SamplePayload > ( ) ;
Console . WriteLine ( $ "Client Got Response { payload . sample } " ) ;
void ServerMessageReceived ( Guid clientId , MessageEnvelope message )
{
Console . WriteLine ( $ "Server Received message { message . Header } " ) ;
server . SendAsyncMessage ( clientId , message ) ;
}
void ClientMessageReceived ( MessageEnvelope message )
{
}
}
ProtoMessageServer
و ProtoMessageClient
توقيعات متطابقة باستثناء المنشئين الذين لا يحصلون على شهادة هذا النموذج هو ما أستخدمه شخصيًا في مشاريعي الأخرى مثل P2PVideocall وMultiplayer Starfighter Game. في الأساس، لديك خادم Relay في مكان ما في شبكتك، والذي يمكن أن يعمل كمحور شبكة محلية في الشبكة المحلية و/أو مفتوح للاتصالات من الإنترنت في حالة تمكين إعادة توجيه المنفذ.
يتصل عملاء الترحيل (الأقران) بخادم الترحيل ويحصلون على إشعارات حول وجود أقران آخرين. يمكن للأقران إرسال رسائل إلى بعضهم البعض من خلال Relay Server، أو مباشرة إلى بعضهم البعض (Udp Holepunch).
تحقق من معلومات P2P Fore التفصيلية
الخادم سلبي تمامًا، مما يسمح للأقران الآخرين باكتشاف الرسائل وإرسالها لبعضهم البعض. بالإضافة إلى ذلك، يتم توفير طرق اجتياز NAT مثل ثقب UDP للسماح بالاتصال المباشر عبر الإنترنت أو الشبكة المحلية (UDP فقط حتى الآن، ولكن لدينا UDP موثوق به).
Relay Server Is Serialization Agnostic
مما يعني أن أي نظير للشبكة المتسلسلة (Protobuff وMessagePack وما إلى ذلك) يمكنه استخدام نفس خادم الترحيل.
لاستخدام خادم Relay، ما عليك سوى إلغاء تحديد الخادم الخاص بك كـ:
var scert = new X509Certificate2 ( "server.pfx" , "greenpass" ) ;
var server = new SecureProtoRelayServer ( 20010 , scert ) ;
server . StartServer ( ) ;
تم بالفعل تكوين خادم الترحيل مسبقًا.
عميل الترحيل هو المكان الذي يتم فيه تنفيذ منطق التطبيق الخاص بك. يمكنك تصفح تطبيقات العميل الخاصة بك على شبكة الإنترنت لاكتشاف والتحدث مع بعضها البعض.
لإلغاء العميل:
// null certificate or default constructor will generate self signed certificate
var cert = new X509Certificate2 ( "client.pfx" , "greenpass" ) ;
var client = new RelayClient ( cert ) ;
client . OnPeerRegistered += ( Guid peerId ) => ..
client . OnPeerUnregistered += ( Guid peerId ) => ..
client . OnMessageReceived += ( MessageEnvelope message ) => ..
client . OnUdpMessageReceived += ( MessageEnvelope message ) => ..
client . OnDisconnected += ( ) => ..
client . Connect ( "127.0.0.1" , 20010 ) ;
تتطابق توقيعات الطريقة وعمليات رد الاتصال مع نموذج العميل/الخادم الأولي (أيضًا مع الحمولات). الفرق الوحيد هو أنه يجب عليك تحديد معرف دليل نظير الوجهة. يأتي ذلك من حدث OnPeerRegistered، عندما يتصل نظير جديد بخادم الترحيل. يضمن Relay Server مزامنة مجموعة الأقران الحالية مع الاتساق النهائي بين جميع الأقران. لذلك سيتلقى الأقران الجدد جميع الأقران المتصلين الآخرين من هذا الحدث وسيتلقى الأقران القدامى تحديثًا.
client . SendAsyncMessage ( destinationPeerId , new MessageEnvelope ( ) { Header = "Hello" } ) ;
client . SendUdpMesssage ( destinationPeerId , new MessageEnvelope ( ) { Header = "Hello" } ) ;
// Or with an async reply
MessageEnvelope response = await client . SendRequestAndWaitResponse ( destinationPeerId ,
new MessageEnvelope ( ) { Header = "Who Are You?" } ) ;
يمكن أن تتجاوز رسائل UDP حد مخطط البيانات البالغ 65.527 بايت. يكتشف النظام رسائل UDP كبيرة الحجم كرسائل ضخمة ويرسلها على شكل مجموعات. سينتهي الاستلام بمحاولة إعادة بناء الرسالة. إذا لم تصل جميع الأجزاء خلال المهلة، فسيتم إسقاط الرسالة. الحد الأقصى لحجم الرسالة لـ UDP هو 16,256,000 بايت.
يستخدم بروتوكول UDP الموثوق به كخوارزمية TCP يتم تنفيذها عبر UDP.
client . SendRudpMessage ( peerId , envelope ) ;
client . SendRudpMessage ( peerId , envelope , innerMessage ) ;
client . SendRudpMessageAndWaitResponse ( peerId , envelope , innerMessage ) ;
client . SendRudpMessageAndWaitResponse ( peerId , envelope ) ;
دعم Nat Traversal/Holepunch:
// Udp
bool result = await client . RequestHolePunchAsync ( destinationPeerId , timeOut : 10000 ) ;
// Tcp
bool result = await client . RequestTcpHolePunchAsync ( destinationPeerId , timeOut : 10000 ) ;
إذا نجحت، فسوف يسمح لك بإرسال رسائل UDP مباشرة بين أقرانك الحاليين والمقصدين لبقية رسائل UDP في كلا الاتجاهين.
هذا امتداد لخادم/عميل الترحيل. الإضافة هي نظام الغرفة حيث يمكن للأقران إنشاء الغرف أو الانضمام إليها، والاستعلام عن الغرف المتاحة، وإرسال رسائل إلى الغرف (البث المتعدد). بالإضافة إلى ذلك، الحفاظ على نفس نظام الرسائل لإرسال رسائل 1-1 بين الأقران.
يمكنك الانضمام إلى غرف متعددة
Room Server Is Serialization Agnostic
مما يعني أنه يمكن لأي نظير للشبكة المتسلسلة (Protobuf وMessagePack وما إلى ذلك) استخدام نفس خادم الغرفة.
تنازل الخادم والعميل
var server = new SecureProtoRoomServer ( 20010 , scert ) ;
server . StartServer ( ) ;
var client1 = new SecureProtoRoomClient ( cert ) ;
لإنشاء/الانضمام ومغادرة الغرف ببساطة:
client1 . CreateOrJoinRoom ( "Kitchen" ) ;
client1 . LeaveRoom ( "Kitchen" ) ;
عمليات الاسترجاعات الغرفة هي على النحو التالي. يتم تشغيل عمليات الاسترجاعات هذه فقط إذا كنت في نفس الغرفة.
client1 . OnPeerJoinedRoom += ( roomName , peerId ) => ..
client1 . OnPeerLeftRoom += ( roomName , peerId ) => ..
client1 . OnPeerDisconnected += ( peerId ) => ..
بالإضافة إلى رد الاتصال القياسي بالرسائل 1-1 لدينا عمليات رد الاتصال برسائل الغرفة.
client1 . OnTcpRoomMesssageReceived += ( roomName , message ) => ..
client1 . OnUdpRoomMesssageReceived += ( roomName , message ) => ..
client1 . OnTcpMessageReceived += ( message ) => ..
client1 . OnUdpMessageReceived += ( message ) => ..
تطبق جميع متغيرات TCP الآمنة مقبس SSL القياسي مع مصادقة/التحقق من صحة TLS. لمزيد من المعلومات راجع: الأمن