제공된 모든 토폴로지에서 16,000개 이상의 동시 클라이언트를 지원하는 사용하기 쉬운 고성능 네트워크 라이브러리입니다.
LAN 또는 인터넷을 통한 분산형 실시간 동시 애플리케이션용으로 설계되었습니다.
높은 처리량의 메시지 전달, P2P, Nat Traversal, Reliable UDP를 위한 인프라를 제공합니다.
이 저장소는 기본 코어 어셈블리와 여러 직렬화 관련 하위 어셈블리로 구성됩니다.
자세한 문서는 Wiki 페이지를 확인하세요.
네트워크 라이브러리에는 원시 바이트부터 P2P 로비와 같은 추상화까지 네트워크 시스템과 관련된 모든 논리가 포함됩니다. 모든 유형의 직렬화에 사용할 수 있는 일반 템플릿을 제공합니다.
원시 바이트로 작동하는 플러그 앤 플레이 고성능 모델입니다. 상위 모델의 베이스로도 사용됩니다.
Tcp Server/Client model
바이트가 일반 소켓처럼 조각화될 수 있습니다.Tcp Byte Message Server/Client
. 조각화 없이 원자성 메시지 전달을 보장합니다.Udp Server/Client
성능에 최적화된 서버를 에뮬레이트하는 UDP 시스템입니다.Reliable Udp Client/Server
.모든 직렬화 프로토콜과 함께 작동할 수 있는 일반 모델을 포함합니다.
Generic Message Server/Client
.Generic MessageProtocol Server/client
.P2P Relay Client/Server
Udp/Rudp/Tcp를 사용하여 통신할 수 있습니다. Tcp&Udp 홀펀치를 지원합니다.P2P Room/Lobby Server/Client
확장입니다.라이브러리는 OS(Windows)가 지원하는 만큼의 클라이언트(약 16k 동적 포트)로 테스트됩니다. RUDP를 포함한 데이터 신뢰성은 인터넷을 통해 광범위하게 테스트되었습니다. Nat Traversal Udp 홀펀칭도 인터넷을 통해 성공적으로 테스트되었습니다.
참고: 라이브러리에는 안전하지 않은 코드와 스택 메모리 할당이 있습니다. 안전하지 않은 섹션은 잘 테스트되었으며 변경되지 않습니다.
메인 어셈블리의 일반 모델은 특정 직렬 변환기를 사용하여 구현됩니다. 이렇게 구분하는 이유는 불필요한 종속성을 피하기 위한 것입니다. 모든 메소드 서명과 사용법은 동일합니다. 여기에는 다음이 포함됩니다.
너겟 패키지를 사용할 수 있습니다:
핵심 네트워크 라이브러리 | 프로토부프 | 메시지팩 | NetSeralizer | 제이슨 |
---|---|---|---|---|
무한 에코 벤치마크는 서버에 메시지 세트를 보내고 에코 응답을 받아 수행됩니다. 각 응답은 새로운 요청을 발생시킵니다. 각 서버 응답은 1개의 에코로 계산됩니다.
각각 1000개의 시드 메시지(32바이트 메시지 + 4헤더):
AMD 라이젠 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바이트):
AMD 라이젠 7 5800H 노트북
클라이언트 수 | 초당 Protobuf 에코 | 초당 보안 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 에코 | 초당 보안 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 |
이 벤치마크에서는 원시 바이트 페이로드가 포함된 메시지 봉투만 보냅니다. 직렬화 관련 성능에 대해서는 직렬화 벤치마크를 참조하십시오.
자세한 정보는 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
참고: 여기서 중요한 성능 설정은 버퍼링 정책으로 버퍼를 사용할지 큐를 사용할지 여부입니다. 메시지가 주로 (버퍼, 오프셋, 개수)와 같은 byte[] 영역인 경우 버퍼를 사용하세요. 메시지가 전체 바이트[](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를 확인하세요.
원시 바이트가 전송되는 기본 서버/클라이언트. 메서드 및 콜백 서명은 바이트 메시지 모델과 동일합니다. 기본 서버/클라이언트에 구현된 프로토콜이 없으므로 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 및 Multiplayer Starfighter Game과 같은 다른 프로젝트에서 개인적으로 사용하는 모델입니다. 기본적으로 네트워크 어딘가에 릴레이 서버가 있습니다. 이 서버는 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 ( ) ;
릴레이 서버는 이미 사전 구성되어 있습니다.
릴레이 클라이언트는 애플리케이션 논리가 구현되는 곳입니다. 클라이언트 애플리케이션을 웹으로 연결하여 서로를 찾고 대화할 수 있습니다.
클라이언트를 선언하려면 다음을 수행하십시오.
// 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 ) ;
메서드 서명과 콜백은 proto 클라이언트/서버 모델(페이로드도 포함)과 동일합니다. 유일한 차이점은 대상 피어 Guid ID를 지정해야 한다는 것입니다. 새로운 피어가 릴레이 서버에 연결될 때마다 OnPeerRegistered 이벤트에서 발생합니다. 릴레이 서버는 현재 피어 세트의 동기화와 모든 피어 간의 최종 일관성을 보장합니다. 따라서 새 피어는 이 이벤트에서 연결된 다른 모든 피어를 수신하고 이전 피어는 업데이트를 수신합니다.
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 등)가 동일한 룸 서버를 사용할 수 있음을 의미합니다.
서버와 클라이언트의 선언
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 소켓을 구현합니다. 더 많은 정보를 확인하려면: 보안