클라이언트간 P2P 통신의 개요

클라이언트간 통신 또는 peer-to-peer 네트워킹(이하 P2P 통신)은 서버를 경유하지 않고 클라이언트 호스트끼리 직접 통신을 하는 것을 일컫습니다. P2P 통신은 다음과 같은 경우에 유용하게 쓰입니다.

  • 서버를 경유해서 통신하기에는 데이터량이 너무 많은 경우: 가령 호스트에서 다른 호스트로 보내야 하는 데이터가 10KB/sec을 넘는 경우 서버를 경유할 경우 클라이언트가 많은 경우 서버에 걸리는 통신량이 어마어마해집니다. 서버 유지 비용에서 통신 회선 속도는 큰 비용을 차지합니다. 따라서 서버를 경유하지 않고 클라이언트끼리 직접 통신하게 해주면 서버 유지 비용을 절감할 수 있습니다.

  • 클라이언트와 서버간에 지리적으로 너무 먼 경우: 예를 들어 클라이언트 A와 B는 브라질에 있지만 서버가 일본에 있는 경우 A가 B에게 직접 줘도 되는 메시지를 서버를 경유할 경우 1개의 메시지는 지구를 한바퀴 돌아야 합니다. 하지만 A와 B간 직접 P2P 통신을 할 수 있는 경우 A가 B에게 직접 주는 메시지는 보다 적은 거리를 거쳐서 B에게 도착할 수 있습니다. 이러한 잇점은 서버가 글로벌 서비스를 하는 경우 더욱 커집니다.

  • 보다 적은 레이턴시를 추구할 경우: 클라이언트가 다른 클라이언트에게 메시지를 보내려고 할 때, 서버를 경유하는 것보다는 직접 대상에게 보내주는 것이 일반적으로 더 빨리 도착합니다. (참고: 항상 그러한 것은 아닙니다. 왜냐하면 인터넷 공급 업체의 장비 구조나 설정에 따라 서버를 경유하는 통신이 고품질로 처리되는 경우도 있기 때문입니다.)
remission.jpg
소규모 멀티플레이 게임에서는 P2P 통신을 활용하는 것이 권장됩니다. 특히 FPS 게임처럼 통신량이 많은 게임일수록요. (사진은 소아암환자를 위한 기능성 게임 Re-mission 스크린샷)

ProudNet의 P2P 통신은 홀펀칭 기술과 강력한 P2P relay 기능을 갖추고 있습니다. 그렇기 때문에 개발자 입장에서는 항상 P2P 통신이 성사되고 있다는 전제하에 간편하게 개발을 진행할 수 있습니다.

ProudNet에서 클라이언트간 P2P 통신은 메시지 단위로 이루어집니다. 1개의 메시지는 1회의 RMI 호출(Remote Method Invocation (원격 메서드 호출) 참고) 에 대응합니다.

ProudNet의 클라이언트간 통신에서는 reliable, unreliable 통신이 모두 가능합니다. (ProudNet의 프로토콜 종류 참고)

클라이언트간 P2P 연결을 위해서는 먼저 서버에서 클라이언트간 P2P 그룹 을 맺어줘야 합니다. 클라이언트는 자신과 같은 P2P 그룹에 속한 클라이언트와만 P2P 통신이 가능합니다.

클라이언트간 P2P 그룹을 서버에서 맺어주면 클라이언트끼리는 일단 서버를 통해 P2P relay 통신을 하게 됩니다. 그 동안에 클라이언트간 P2P 홀펀칭을 백그라운드로 진행합니다. 만약 P2P 홀펀칭이 성공하게 되면 그때부터 클라이언트간 통신은 서버를 경유하지 않고 직접 이루어지게 됩니다. 이러한 특징 때문에, ProudNet에서는 P2P 그룹을 맺거나 변경한 즉시 클라이언트간 메시지 송수신이 가능합니다. 그리고 P2P 그룹을 맺자마자 클라이언트간 통신을 시작하면 서버에서 수 초 동안 서버측 통신량이 일시적으로 약간 증가하게 됩니다. 이는 호스트간 홀펀칭 기능이 작용하기 때문입니다.

relay_then_direct.png
P2P 통신 시작후의 내부 진행

홀펀칭된 클라이언트끼리의 P2P 통신은 UDP와 ProudNet 자체 개발된 Reliable UDP로 이뤄집니다. 그러나 홀펀칭이 성공하기 전까지는 UDP 또는 TCP를 통해 P2P relay를 하게 됩니다.

클라이언트에서 P2P 통신을 위해 사용하는 UDP 포트는 서버와 연결할 때 사용하는 UDP 포트와 동일합니다.