ProudNet.Eng
WebsiteProud ConsoleLanguage
  • 🌐ProudNet
    • ProudNet Introduction
    • Download and Install
      • How to verify your ProudNet license
      • AMI
    • Project Settings
      • C++
      • C#
      • Mac Xcode
      • Linux
      • Unity3D
        • iOS Build
      • Unreal Engine 4
      • Running the PIDL Compiler
    • Using ProudNet
      • Server and Client
        • Utilization of Server
        • Utilization of Client
      • RMI
        • Utilization of RMI
      • PIDL
        • Utilization of PIDL
      • Event handling
      • Communication messages
      • P2P Communication
        • Using P2P communication
    • Utilization of ProudNet
      • How to use
      • Tips for performance
    • Using DB in ProudNet
      • DB Cache System ver.2
        • DB Cache Theory and Understanding
        • Install DB Cache and Set Up Network
        • DB Cache Server and Client
        • DB Cache usage and application
          • Utilization of DB Cache
      • ADO API
      • ODBC API
    • ProudNet Utility
  • ProudNet Note
    • Technical Notes
      • Main Loop
      • Setting up a server firewall
      • Encryption and decryption
      • What to do in case of an error
      • List of error messages
      • Synchronizing Character Position
      • Client-Server Communication
      • MiniDump (Error Dump System)
      • [Version 1.6] Server-to-Server LAN Communicator
    • Glossary
    • Sample examples
  • 🌐Proud Service
    • Guide for Console
    • ProudChat
      • Download SDK
        • C++
        • C#
        • Unity3D
        • Unreal Engine 4
      • Features in Console
Powered by GitBook
On this page
  • Registering and Using Proxy & Stub Communication Objects
  • Event
  • - Common to client and server
  • - Server
  1. ProudNet Note
  2. Technical Notes

Client-Server Communication

PreviousSynchronizing Character PositionNextMiniDump (Error Dump System)

Last updated 1 year ago

When a client connects to a server, communication is first established over TCP.

In the meantime, if a successful UDP holepunch to the server occurs in the background, UDP communication is possible, but until then, both reliable, is replaced by TCP. However, after a successful UDP holepunch, is replaced by UDP.

Clients each have a TCP port and a UDP port, and the server has one TCP listening port and one or more UDP ports. Clients maintain a TCP connection to the server and select one of the server-side UDP ports, meaning that the server shares multiple UDP ports evenly among all connected clients.

For example, if 40,000 clients communicate with a server that has 20,000 open UDP ports, there will be two clients communicating for each UDP port on the server side.

Registering and Using Proxy & Stub Communication Objects

To add communication to the server and client, we will create a Common project that will be used by both the server and client for convenience, and prepare a PIDL file. In the prepared PIDL file, define the protocol for sending communication from the server to the client.

Global S2C 3000
{
   Chat(Proud::StringA txt);
}

Compiling the above PIDL file will create a Proxy and Stub object.

How to Use Proxy Objects

First, include the Header wherever you want to use it.

// Server: Server ▶ As a Client
// To make the call,
// the server uses the Proxy object to make the call.
// Declare in header file
// Since we assume we are creating a Common project, 
// we will include the generated files 
// from the folder in the Common project.
#include "../Common/S2C_proxy.h"
  
// Declare in a cpp file
#include "../Common/S2C_proxy.cpp"

Create a proxy and register it with the server object.

// Creates an object.
S2C::Proxy g_S2CProxy;
  
void main()
{
    // The Server object you created 
    // in the Server description.
    CNetServer* srv = 
         ProudNet::CreateServer();
    Svr->AttachProxy(&g_S2CProxy);
  
    // Omitted below
}

We registered it by passing a pointer to the created Proxy object using a function called AttachProxy. AttachProxy can register multiple types of PIDLs by managing them internally as an array. Once registered, you can use the functions of the Proxy object to communicate.

// The HostID and RmiContext
// are added automatically.
// Insert the HostID value of the Client 
// you want to send as hostID.
g_S2CProxy.Chat(
         hostID, 
         RmiContext::ReliableSend, 
         “Send Message”);

Like proxy, stub includes a header wherever you want to use it.

Client:
 Server ▶ Since it is a client, the client
 includes a stub object to receive calls.
// Declare in header file 
// Since we assumed
// we were creating a Common project, 
// we would include the file created in the Common folder.
#include "../Common/S2C_stub.h"
  
// Declare in a CPP file
#include "../Common/S2C_stub.cpp"

In the case of the Stub object, you must create and use an inherited object because it is a defining function of the protocol to be received. If you register it using the AttachStub function, it will be called when that call comes in. Inside the generated Stub object, a Define is created, which allows you to avoid having to modify your cpp and h files separately when you change protocols.

#define DECRMI_C2S_Chat bool Chat(
        Proud::HostID remote,
        Proud::RmiContext &rmiContext,
        const Proud::StringA txt)

Among the define statements specified in the Stub Class, declare DEFRMI_NameSpace_function name in the header file of the inherited object and DECRMI_NameSpace_function name (Class_Name) in the cpp.

class CS2CStub : public S2C::Stub
{
public:
  
// The protocol is handled
// as a define statement in the stub 
// so that the user does not have to modify the class if it changes.
// If it is 'DEFRMI_NameSpace_FunctionName',
// declare it in the header.
    DECRMI_S2C_Chat;
};
CS2CStub g_S2CStub;
  
// ‘DEFRMI_Protocol Taxonomy name_protocol name(
//               Inherited class name)’
// then declare it in the CPP.
DEFRMI_S2C_Chat(CS2CStub)
{
    printf( 
         "[Client] HostID:%d, text: %s”, 
         remote, 
         txt);
  
         // It must return true
    return true;
}

Returning 'True' means that it has been processed. If it returns 'False', the OnNoRmiProcessed Event is called because the user has not processed the protocol. Of the function arguments called with DEFRMI_S2C_Chat, remote is the value of the HostID of the other party that called the RMI. By invoking the Proxy with this ID value, you can send communication to the desired party.

Now we will register the Stub object we created with the Client object.

CNetClient *client 
         = ProudNet:CreateClient();
client->AttachStub(&g_S2CStub);
// Omitted below

The AttachStub function is also managed internally as an array, and is registered by passing a pointer to it.

How to Use Proxy Objects

Create classes like Proxy, Stub, etc. that are included in the PIDL compilation output.

CommonC2C.Proxy c2cProxy = new CommonC2C.Proxy();
CommonC2S.Proxy c2sProxy = new CommonC2S.Proxy();

Create proxies and attach them to clients.

Nettention.Proud.NetClient netClient = new Nettention.Proud.NetClient();
netClient.AttachProxy(c2cProxy);
netClient.AttachProxy(c2sProxy);

How to Use Stub Objects

CommonS2C.Stub s2cStub = new CommonS2C.Stub();
CommonC2C.Stub c2cStub = new CommonC2C.Stub();

Like Proxy, you create stub where you want to use them and attach them to the Client.

Unlike the C++ version, the DotNet version has the stub as a delegate.

// Set the delegate to handle the stub.
s2cStub.NotifyLocalHeroViewersGroupID = NotifyLocalHeroViewersGroupID; //<- Set up the functions below.

//Similarly, create and set up the functions below.
s2cStub.RemoteHero_Appear = RemoteHero_Appear;

s2cStub.RemoteHero_Disappear = RemoteHero_Disappear;

c2cStub.P2P_LocalHero_Move = P2P_LocalHero_Move;


...

netClient.AttachStub(s2cStub);

netClient.AttachStub(c2cStub);

...


//Create a function for the delegate.
bool NotifyLocalHeroViewersGroupID(Nettention.Proud.HostID remote, Nettention.Proud.RmiContext rmiContext, Nettention.Proud.HostID localHeroViewersGroupID)
{
    ...
    return true;
}

Initialize Nettention.Proud.NetConnectionParam, call Nettention.Proud.NetClient.Connect() on and connects to the server.

Nettention.Proud.NetConnectionParam param = new Nettention.Proud.NetConnectionParam();

//Match the protocolVersion.
param.protocolVersion.Set(new System.Guid("{0x7b7e9c20,0x309c,0x4364,{0xb4,0x9c,0xc6,0xc,0xcd,0x25,0xaf,0xa0}}"));

//Set the port to connect to.
param.serverPort = 32222;

//Set the IP address to connect to.
param.serverIP = serverAddr;

netClient.Connect(param);

Be sure to check your traffic after development. Traffic requires checking the amount of communication on each client, server (and Super Peer if you use Super Peer), etc. and removing unnecessary traffic. To check your traffic, you can use the methods below.

  • Use a tool like NetLimiter.

  • There is a way to run exactly as many processes as you want to use on one computer, and then check the number of bytes sent and received per interval in the Task Manager.

  • You can use ProudNet's internal function CNetServer::GetStats(CNetServerStats &outVal); to get real-time traffic sent and received per second, the number sent or received, and more. If the total traffic from a single client is roughly 20-30 KB or more, you may experience issues with your international service.

Tools like NetLimiter are recommended to be deleted after use. Kernel Hooking puts 20x the original speed burden on the core holding the communication daubers.

Event

- Common to client and server

Using errorInfo -> ToString(); in the parameter errorInfo, you can easily get information about the problem.

Event
Description

OnError

Callbacks for information about errors or usage issues that occur inside ProudNet.

OnWarnning

Call back information that is not critical but potentially problematic.

OnInformation

Callbacks for information about internal context and tracking, etc.

OnException

Call internal Exception error information.

OnNoRmiProcessed

Declared in the PIDL, but called when the Event is not inherited from the Stub, or when the user returns false.

- Server

This can be used for performance testing and more.

Event
Description

OnUserWorkerThreadBegin

Called when a Thread in the User Worker Thread Pool is started.

OnUserWorkerThreadEnd

Called at the end of a thread in the User Worker Thread Pool.

unreliable messaging
reliable messaging