19.1Concept
Client communication or peer-to-peer networking(hereafter, P2P communication) refers to a direct communication between client hosts without involving a server. This is very useful in the following cases.
Data to be transmitted is too large for a server to handle
Client and server are geographically too distant for a continuous, effective, and low latency networking
Lower latency is required
If players need to synchronize with each other, total amount of traffic server needs to handle is greatly reduced if P2P is used.
However, it must be noted that as number of P2P connections increases, there is a burden on client traffic. Also, there could potentially be an attempt to hack by a malicious player. Critical data should be passed onto the server. ProudNet manages P2P group assembly and disassembly in a server to increase security.
19.2Operation Guide
Server creates a P2P group by a CreateP2PGroup function call.
Clients receive callback indicating newly formed P2P group though INetClientEvent::OnP2PMemberJoin.
Through OnP2PMemberJoin function, each client receives the HostIDs of the clients (members) that have joined in the group.
The following functions are used by a server to manipulate P2P group, and the respective callbacks for clients.
Adding a new member to a P2P group
Server Call: CNetServer::JoinP2PGroup
Client Callback: INetClientEvent::OnP2PMemberJoin
Delete a member from a P2P group
Server Call: CNetServer::LeaveP2PGroup
Client Callback: INetClientEvent::OnP2PMemberLeave
Delete a P2P group
Server Call (CNetServer::DestroyP2PGroup
Client Callback: (INetClientEvent::LeaveP2PGroup)
Example
Processing a visual group during a game play
CreateP2PGroup is called when a client connects
JoinP2PGroup is called when another client enters the view
LeaveP2PGroup is called when a client exits the view
DestroyP2PGroup is called when the client disconnects
Chatting
CreateP2PGroup is called when a chat group is created
JoinP2PGroup is called when another client joins the chat room
DestroyP2PGroup is called when the chat room is closed
With a simple addition of few lines, P2P communication can be enabled.
//File Name C2C – Client - //Client protocol definition file global C2C 4000 // client-to-client RMI, // The initial messageID = 4000 { P2PChat ([in] Proud::StringA txt); }
Δ PIDL Addition
Server
CNetServer *srv = Proud:: CreateServer(); HostID groupHostID;
Δ Object
// Warning! Do not use GetClientHostIDs // in the real server. // Manage them separately. HostID list[100]; int listCount = srv->GetClientHostIDs( list, 100); groupHostID = srv->CreateP2PGroup( list, listCount, ByteArray());
Δ P2P group creation
g_S2CProxy.P2PChat(
groupHostID,
RmiContext::ReliableSend,
L"Hello~~~!");
Δ Communication with a P2P group
srv->DestroyP2PGroup( groupHostID);
Δ P2P Group closure
Client
Only the added parts are described here. Previously described parts are omitted.
// Header File Addition #include “../C2C_Stub.h” // CPP File Addition #include “../C2C_Stub.cpp”
Δ Header
client ->AttachProxy( &g_C2CProxy); client ->AttachStub( &g_C2CStub);
Δ Server & Client addition
Class CClientEventSink : public INetClientEvent { // Called each time a new member joins // to all // existing members. virtual void OnP2PMemberJoin( HostId memberHostID, HostID groupHostID, int memberCount, const ByteArray &customField) {} // Called each time a member exits // to all existing members. virtual void OnP2PMemberLeave( HostID memberHostID, HostID groupHostID, int memberCount) {} // The rest is omitted. }
Δ Event Object - additions
Class C2CStub
: public C2C::Stub
{
DECRMI_C2C_P2PChat;
}
DEFRMI_C2C_P2PChat(C2CStub)
{
Printf(
“[client] %d, %s”,
remote,
txt);
}
C2CStub g_C2CStub;
Δ Object to receive C2C communication
C2C::Proxy g_C2CProxy;
Δ Object to send C2C communication
Tip!
Is the number of transmissions on an unreliable P2P unlimited?
Client's network traffic per transmission increases by (n-1)^2 per peer in a P2P communication due to the nature that one transmission needs to be sent to each of the clients. When there's too much traffic, network can become unstable or even cause disconnections for users.
Traffic amount needs to be minimized for P2P synchronization especially in places with a lot of players where latencies are not as important, such as a village.
For better performance, using Unreliable is recommended for information (such as Move Packet) that is sent continuously and could be lost.
Client with Hole-Punching completion
Use reliable UDP internally. (Reliable UDP produces by design retransmits packets which can increase traffic compared to regular UDP).
Client with Hole-Punching incompletion
The communication is performed in relay through a server. If unreliable connection is chosen, then UDP is used to communicate with a server. Otherwise, if reliable connection is chosen, relaying is done with a TCP connection.