19.P2P간 통신

19.1개념

Client 통신 또는 peer-to-peer 네트워킹(이하 P2P 통신)은 Server를 경유하지 않고 Client 호스트끼리 직접 통신을 하는 것을 일컫습니다. 다음과 같은 경우 유용합니다.

  1. Server를 경유해서 통신하기에는 Data량이 너무 많은 경우

  2. Client와 Server간에 지리적으로 너무 먼 경우

  3. 보다 적은 Latency를 추구할 경우

Layer간 이동 동기화를 할 때 P2P 기능을 사용하여 Server의 Traffic을 줄일 수 있습니다.

그림 19-1P2P사용하지 않고 한 케릭터의 시야 그룹내 동기화를 관리 하는 예

그림 19-2P2P사용하여 한 케릭터의 시야 그룹의 동기화를 관리 하는 예

하지만 반대로 P2P Connection의 수가 많아지면 Client의 Traffic이 과도해 질 수 있음을 인지하셔야 합니다. 또한 항시 해킹의 위험이 있기 때문에 공격 판정 여부 같은 중요한 Data는 Server에서도 확인해주어야 합니다. ProudNet에서는 해킹에 대한 안정성을 높이기 위하여 P2P의 그룹 생성과 해제 등의 모든 것을 Server에서 관리 해 주고 있습니다.

19.2사용법

  1. Server에서 CreateP2PGroup 함수 호출을 통하여 P2P그룹을 만듭니다.

  2. Client는 INetClientEvent::OnP2PMemberJoin을 통하여 P2P그룹이 생성 되었음을 Callback받게 됩니다.

  3. OnP2PMemberJoin 함수를 통하여 그룹에 들어온 Client들과 Member의 HostID값을 받습니다.

아래는 Server에서 P2P그룹의 변화를 주기 위한 함수 호출과 Client에서 받게 될 Callback입니다.

P2P 그룹에 새로운 member 추가

P2P 그룹에 새로운 member 제거

P2P 그룹을 제거

사용 예

간단한 코드 추가로 P2P통신을 할 수 있습니다.

//File Name C2C – Client간 
//Protocol의 정의파일 입니다.
global C2C 4000 
// client-to-client RMI, 
// 최초메시지ID = 4000
{
    P2PChat ([in] Proud::StringA txt);
}

Δ PIDL 추가

Server

CNetServer *srv 
         = Proud:: CreateServer();
HostID groupHostID;

Δ 객체

// 주의! 실 Server에서는 
// GetClientHostIDs를 이용하지 말고, 
// 따로 관리하세요.
HostID list[100];
int listCount = 
        srv->GetClientHostIDs(
             list, 
             100);
  
groupHostID = 
        srv->CreateP2PGroup(
             list, 
             listCount, 
             ByteArray());

Δ P2P그룹 생성

g_S2CProxy.P2PChat(
         groupHostID, 
         RmiContext::ReliableSend,
         L"Hello~~~!");

Δ P2P그룹에 통신 보내기

srv->DestroyP2PGroup(
       groupHostID);

Δ P2P Group 파괴하기

Client

추가적으로 사용되는 부분 외에는 생략합니다.

// Header File 추가
#include “../C2C_Stub.h”
// CPP File 추가
#include “../C2C_Stub.cpp”

Δ Header

client ->AttachProxy(
         &g_C2CProxy);
client ->AttachStub(
         &g_C2CStub);

Δ Server & Client 구조에서 추가 되어야 할 부분

Class CClientEventSink 
         : public INetClientEvent
{
       // 새로 추가되는 Group의 
       // member수 만큼 연속으로 
       // 호출됩니다.
       virtual void OnP2PMemberJoin(
           HostID memberHostID, 
           HostID groupHostID, 
           int memberCount, 
           const ByteArray &customField) {}
  
       // 제거되는 Member수 만큼 
       // 연속으로 호출됩니다.
       virtual void OnP2PMemberLeave(
           HostID memberHostID, 
           HostID groupHostID, 
           int memberCount) {}
  
       // 기타 생략
}

Δ Event 객체 - 추가로 사용되는 부분

Class C2CStub 
         : public C2C::Stub
{
DECRMI_C2C_P2PChat;
}
DEFRMI_C2C_P2PChat(C2CStub)
{
   Printf(
          “[client] %d, %s”, 
          remote, 
          txt);
}
C2CStub g_C2CStub;

Δ C2C간 통신을 받기 위한 객체

C2C::Proxy g_C2CProxy;

Δ C2C간 통신을 보내기 위한 객체

Unreliable P2P로 보낼 수 있는 수는 무제한 인가?

Move Packet과 같이 자주 보내고 손실되어도 괜찮은 정보에는 Unreliable을 사용하는 것이 성능상 이득입니다.