提供されるすべてのトポロジで 16,000 を超える同時クライアントをサポートする、高性能で使いやすいネットワーク ライブラリ。
LAN またはインターネットを介した分散リアルタイム同時アプリケーション用に設計されています。
高スループットのメッセージ パッシング、P2P、Nat Traversal、Reliable Udp のためのインフラストラクチャを提供します。
このリポジトリは、メイン コア アセンブリといくつかのシリアル化固有のサブ アセンブリで構成されます。
詳細なドキュメントについては Wiki ページを参照してください。
ネットワーク ライブラリ。生のバイトから P2P ロビーなどの抽象化まで、ネットワーク システムに関連するすべてのロジックが含まれます。あらゆるタイプのシリアル化で使用できる汎用テンプレートを提供します。
生バイトで動作するプラグアンドプレイ高性能モデル。上位機種のベースとしても使用されます。
Tcp Server/Client model
では、通常のソケットと同様にバイトが断片化される可能性があります。Tcp Byte Message Server/Client
バイトが 4 バイト長のヘッダーとともに送信されます。これにより、断片化することなくアトミックなメッセージ配信が保証されます。Udp Server/Client
サーバーがパフォーマンスを最適化してエミュレートされる udp システム。Reliable Udp Client/Server
。任意のシリアル化プロトコルで動作できる汎用モデルが含まれます。
Generic Message Server/Client
。Generic MessageProtocol Server/client
ですが、ヘッダー/メタデータとして使用される「MessageEnvelope」キャリア クラスが追加されています。P2P Relay Client/Server
では、ピア (クライアント) がリレー サーバーを介してお互いを発見し、Udp/Rudp/Tcp を使用して通信できます。 Tcp&Udpホールパンチをサポートします。P2P Room/Lobby Server/Client
拡張。ライブラリは、OS (Windows) がサポートする数のクライアント (約 16,000 の動的ポート) でテストされています。 RUDP を含むデータの信頼性は、インターネット経由で広範囲にテストされます。 Nat Traversal Udp ホールパンチもインターネット経由でテストされ、成功しました。
注: ライブラリには安全でないコードとスタック メモリ割り当てがあります。安全でないセクションは十分にテストされており、変更されることはありません。
メイン アセンブリの汎用モデルは、特定のシリアライザーを使用して実装されます。この分割の理由は、不要な依存関係を避けるためです。すべてのメソッドのシグネチャと使用法は同一です。それには以下が含まれます:
Nuget パッケージが利用可能です:
コアネットワークライブラリ | プロトブフ | メッセージパック | ネットセラライザー | ジソン |
---|---|---|---|---|
Infinite Echo ベンチマークは、一連のメッセージをサーバーに送信し、エコー応答を取得することによって実行されます。応答ごとに新しいリクエストが発生します。各サーバー応答は 1 エコーとしてカウントされます。
それぞれ 1000 のシード メッセージ (32 バイトのメッセージ + 4 ヘッダー):
AMD Ryzen 7 5800H ノートパソコン
クライアントの数 | 1 秒あたりの TCP エコー | 1 秒あたりの SSL エコー |
---|---|---|
100 | 53,400,000 | 41,600,000 |
1000 | 43,600,000 | 22,200,000 |
5000 | 43,400,000 | 21,800,000 |
10000 | 4,280万 | 21,700,000 |
インテル i9 13980HX ノートパソコン
クライアントの数 | 1 秒あたりの TCP エコー | 1 秒あたりの 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 バイト):
AMD Ryzen 7 5800H ノートパソコン
クライアントの数 | Protobuf エコー/秒 | 1 秒あたりの安全な 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 エコー/秒 | 1 秒あたりの安全な 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、offset、count) などの byte[] の領域である場合は、Buffer を使用します。メッセージがフル byte[] (0 から最後まで) の場合は、Queue を使用します。
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 を参照してください。
生のバイトが転送されるベースサーバー/クライアント。メソッドとコールバックの信号はバイト メッセージ モデルと同じです。基本サーバー/クライアント上に実装されたプロトコルがないため、MTU サイズによってはバイトが断片化される可能性があります。
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 ) ;
シリアル化ネットワークは、コア ライブラリによって提供される汎用クラスの実装であり、すべてのシリアル化プロトコルに適用できます。
詳細については、シリアル化されたネットワークを参照してください。
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 やマルチプレイヤー スターファイター ゲームなどの他のプロジェクトで個人的に使用しているものです。基本的に、ネットワークのどこかにリレー サーバーがあり、LAN 内のローカル ネットワーク ハブとして機能したり、ポート転送が有効になっている場合はインターネットからの接続を開くことができます。
リレー クライアント (ピア) はリレー サーバーに接続し、他のピアの存在に関する通知を受け取ります。ピアは、リレー サーバーを介して相互にメッセージを送信することも、直接相互にメッセージを送信することもできます (Udp ホールパンチ)。
P2P の詳細情報を確認してください
サーバーは完全に受動的であり、他のピアが相互にメッセージを検出して送信できるようになります。さらに、インターネットまたは LAN 経由での直接通信を可能にするために、UDP ホールパンチなどの NAT トラバーサル方式が提供されています (これまでのところ UDP のみですが、信頼できる udp があります)。
Relay Server Is Serialization Agnostic
、シリアル化されたネットワーク ピア (Protobuff、MessagePack など) が同じリレー サーバーを使用できることを意味します。
リレー サーバーを使用するには、次のようにサーバーを宣言するだけです。
var scert = new X509Certificate2 ( "server.pfx" , "greenpass" ) ;
var server = new SecureProtoRelayServer ( 20010 , scert ) ;
server . StartServer ( ) ;
中継サーバーはあらかじめ設定されています。
リレー クライアントは、アプリケーション ロジックが実装される場所です。クライアント アプリケーションを Web で検索し、相互に通信できます。
クライアントを宣言するには:
// 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 ) ;
メソッド シグネチャとコールバックは、プロト クライアント/サーバー モデル (ペイロードも含む) と同一です。唯一の違いは、宛先ピアの GUID ID を指定する必要があることです。新しいピアがリレー サーバーに接続されるたびに、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 メッセージをジャンボ メッセージとして検出し、チャンクで送信します。 end with を受信すると、メッセージの再構築が試行されます。すべての部分がタイムアウト内に到着しない場合、メッセージはドロップされます。 udp の最大メッセージ サイズは 16,256,000 バイトです。
信頼性の高い udp プロトコルは、UDP 上に実装された TCP アルゴリズムとして使用されます。
client . SendRudpMessage ( peerId , envelope ) ;
client . SendRudpMessage ( peerId , envelope , innerMessage ) ;
client . SendRudpMessageAndWaitResponse ( peerId , envelope , innerMessage ) ;
client . SendRudpMessageAndWaitResponse ( peerId , envelope ) ;
Nat Traversal/ホールパンチのサポート:
// 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 など) が同じ Room サーバーを使用できることを意味します。
サーバーとクライアントの宣言
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 バリアントは、TLS 認証/検証を備えた標準 SSL ソケットを実装しています。詳細については、「セキュリティ」を参照してください。