# How to use

## Getting ping time between hosts

As a way to obtain interhost latency (ping time or lag) from ProudNet, the ping time obtained is the roundtrip latency, which is the time taken to send a message from one host to the other and then respond immediately to it from the other host.

### **-** Function to obtain latency of one client from the server

<table data-full-width="false"><thead><tr><th>C++ function</th><th>C# function</th><th>Description</th><th data-hidden>C++</th><th data-hidden>C#</th></tr></thead><tbody><tr><td>Proud.CNetServer.GetLastPingSec</td><td>Nettention.Proud.NetServer.GetLastReliablePingSec</td><td>Get the last wait time in seconds for that client.</td><td>Proud.CNetServer.GetLastPingSec</td><td></td></tr><tr><td>Proud.CNetServer.GetLastUnreliablePingMs</td><td>Nettention.Proud.NetServer.GetLastUnreliablePingMs</td><td>Get the last latency for that client in Ms.</td><td>Proud.CNetServer.GetLastUnreliablePingMs</td><td></td></tr><tr><td>Proud.CNetServer.GetRecentPingSec</td><td>Nettention.Proud.NetServer.GetRecentReliablePingSec</td><td>Get the last wait time in seconds for that client.</td><td>Proud.CNetServer.GetRecentPingSec</td><td></td></tr><tr><td>Proud.CNetServer.GetRecentUnreliablePingMs</td><td>Nettention.Proud.NetServer.GetRecentUnreliablePingMs</td><td>Get the last latency for that client in Ms.</td><td>Proud.CNetServer.GetRecentUnreliablePingMs</td><td></td></tr></tbody></table>

### **-** Functions to get the latency of the server or other P2P connected clients from the client

<table data-full-width="false"><thead><tr><th width="392">C++ function</th><th width="505">C# function</th></tr></thead><tbody><tr><td>Proud.CNetClient.GetLastUnreliablePingSec</td><td>Nettention.Proud.NetClient.GetLastUnreliablePingSec</td></tr><tr><td>Proud.CNetClient.GetLastUnreliablePingMs</td><td>Nettention.Proud.NetClient.GetLastUnreliablePingMs</td></tr><tr><td>Proud.CNetClient.GetLastReliablePingSec</td><td>Nettention.Proud.NetClient.GetLastReliablePingSec</td></tr><tr><td>Proud.CNetClient.GetLastReliablePingMs</td><td>Nettention.Proud.NetClient.GetLastReliablePinMs</td></tr><tr><td>Proud.CNetClient.GetRecentUnreliablePingSec</td><td>-</td></tr><tr><td>Proud.CNetClient.GetRecentUnreliablePingMs</td><td>Nettention.Proud.NetClient.GetRecentUnreliablePingMs</td></tr><tr><td>Proud.CNetClient.GetRecentReliablePingSec</td><td>Nettention.Proud.NetClient.GetRecentReliablePingSec</td></tr><tr><td>Proud.CNetClient.GetRecentReliablePingMs</td><td>Nettention.Proud.NetClient.GetRecentReliablePingMs</td></tr></tbody></table>

{% hint style="warning" %}
Starting with version <mark style="color:orange;">1.7.40679-master</mark>, we added a new function to get the latency from the client to the server.\
Previous functions like <mark style="color:orange;">GetLast\~</mark> or <mark style="color:orange;">GetRecent\~</mark> had a problem with ping pong being delayed when the network condition was not smooth.&#x20;

If you have access to <mark style="color:orange;">1.7.40679</mark> or later, we recommend using the function to get the latency with the newly added server.
{% endhint %}

{% hint style="info" %}
**Reliable message** **delivery** is a two-way communication method, which means that sending and receiving times are slower than **Unreliable**, but the order of sending and receiving and the certainty of arrival are guaranteed.
{% endhint %}

{% hint style="info" %}
**Unreliable message delivery** is a one-way communication method that has a faster send and receive time than **Reliable**, but the order in which messages are sent and received can be out of order and arrival is not guaranteed.
{% endhint %}

## Communicating between programs in different languages

Sometimes you want two programs to communicate with ProudNet, but in different programming languages. In these cases, the PIDL compiler will generate proxies and stubs in two or more languages, and each program can then grab and write what it needs.

Basic types like int, double, and string are already provided by ProudNet's wrapping modules for languages other than C++. However, in different languages, these primitive types are named differently by default. For example, in C#, the string class is <mark style="color:orange;">System.String</mark>, whereas in C++ it is <mark style="color:orange;">std::string</mark>, <mark style="color:orange;">std::wstring</mark>, <mark style="color:orange;">ATL::CString</mark>, <mark style="color:orange;">Proud::String</mark>.

To address this, the PIDL compiler provides the ability to change the type of variables in the generated proxy and stub to be language specific if desired.

Below is an example of usage.

```cpp
// Rename TypeA to TypeB when creating proxy,stub in C# language.
rename cs(TypeA, TypeB);
// Rename TypeC to TypeD when creating proxy,stub in C++ language.
rename cpp(TypeC, TypeD);
 
global XXX 2000
{
    Foo([in]TypeA a);  // When creating a proxy,stub in C# language, it will be Foo(TypeB a),
    Goo([in]TypeC c);  // When creating a proxy,stub in C++ language, it will be Goo(TypeD c).
}
```

## User-defined data for each host (Host Tag)

The <mark style="color:orange;">Proud.HostID</mark> is included for identification when receiving RMI or event callbacks. When developing a game server, if you get a <mark style="color:orange;">Proud.HostID</mark>, you can retrieve an object for that Host based on that value and then work with it, which is how the ProudNet sample program is built.

A <mark style="color:orange;">Host Tag</mark> is identifying data, other than the Host ID, that you can define for the local host and other hosts.

You can use them to make your program perform better.

```cpp
OnClientJoin(CNetClientInfo* clientInfo)
{
    // If the host leaves during the execution of the OnClientJoin function, SetHostTag may fail
    // so it is recommended to check the following.
    CNetClientInfo outInfo;
    if(m_client->GetClientInfo(clientInfo->m_HostID,outInfo))
    {
        Host* r = new Host;
        SetHostClientTag(clientInfo->m_HostID, r);
    }
}
 
DEFRMI_XXX_YYY(MYCLASS)
{
    void* tag = RmiContext.m_hostTag;
    // If SetHostTag failed, RmiContext.m_hostTag may be NULL and needs to be checked.
    if(tag != NULL)
    {
        Host* obj = (Host*)tag;     // No cost to find 
        obj->Something();
    }
}
```

**Example when Host Tag is not used**

```cpp
DEFRMI_XXX_YYY(MYCLASS)
{
    Host* obj = Lookup(HostID);  // Incurring the cost of finding
    if(obj != NULL)
        obj->Something();
}
```

<figure><img src="/files/N2lmlCGiBdZIdbiuwj0F" alt=""><figcaption><p>Host Tag</p></figcaption></figure>

The <mark style="color:orange;">Host Tag</mark> is specified by the following methods.

| C++ function                | C# function                           |
| --------------------------- | ------------------------------------- |
| Proud.CLanClient.SetHostTag | -                                     |
| Proud.CLanServer.SetHostTag | -                                     |
| Proud.CNetClient.SetHostTag | Nettention.Proud.NetClient.SetHostTag |
| Proud.CNetServer.SetHostTag | Nettention.Proud.NetServer.SetHostTag |

{% hint style="warning" %} <mark style="color:orange;">CLanClient</mark> and <mark style="color:orange;">CLanServer</mark> are not supported starting in <mark style="color:orange;">version 1.7</mark>.

<mark style="color:orange;">NetClient</mark> and <mark style="color:orange;">NetServer</mark> take over the roles of <mark style="color:orange;">CLanClient</mark> and <mark style="color:orange;">CLanServer</mark>.
{% endhint %}

The <mark style="color:orange;">Host Tag</mark> is received via <mark style="color:orange;">Proud.RmiContext.m\_hostTag</mark> and <mark style="color:orange;">Proud.CNetPeerInfo.m\_hostTag</mark> and is not synchronized over the network, so it is not propagated to the other party.

## Setting up a Thread Pool

The network client module <mark style="color:orange;">CNetClient</mark> and the server module <mark style="color:orange;">CNetServer</mark> in ProudNet use two types of [**Thread Pool**](/proudnet.eng/proudnet-note/dictionary.md#thread-pool).

* <mark style="color:orange;">Networker thread pool</mark>: Used exclusively for internal processing of the ProudNet, handling socket I/O, etc.
* <mark style="color:orange;">User worker thread pool</mark>: For running user-defined routines. Handle RMI or callback events, etc.

For best performance, create thread pools explicitly and set them up in the Network module if you want certain thread pools to be shared instead of each module owning them.

{% hint style="info" %}
Currently, you need to include <mark style="color:orange;">ProudNetServer.h</mark> to use this feature on the client end, but starting with <mark style="color:orange;">1.7.36365</mark>, you do not need to include <mark style="color:orange;">ProudNetServer.h</mark> to use it.
{% endhint %}

{% hint style="danger" %}
A user-created thread pool object will throw an exception if it is destroyed before all network modules are destroyed.
{% endhint %}

Below is the pseudo code involved in the overall flow.

{% tabs %}
{% tab title="C++" %}

<pre class="language-cpp"><code class="lang-cpp">// The object responsible for callbacks for threadpool startup/shutdown.  
<strong>Proud::CThreadPoolEventFunctional e;  
</strong>  
// In other words, put in a routine for starting/shutting down the threadpool. (Optional)  
e.OnThreadBeginFunction = [](){...};  
e.OnThreadEndFunction = [](){...};  
  
// Creates a thread pool object with as many threads as the number of CPUs.  
Proud::CThreadPool* p = Proud::CThreadPool::Create(&#x26;e, GetNoofProcessors());  
// If you want to have two threads
Proud::CThreadPool* p = Proud::CThreadPool::Create(&#x26;e, 2);
 
// ----------Forward the object to which this thread pool is registered as a parameter.----------
// For the server end
<strong>Proud::CStartServerParameter param;
</strong>param.m_externalUserWorkerThreadPool = p;
 
// For the client end
Proud::CNetConnectionParam param;
// Types of Thread Models in a ProudNet See also Open the link in a new window
param.m_userWorkerThreadModel = Proud::ThreadModel::ThreadModel_UseExternalThreadPool;
param.m_externalUserWorkerThreadPool = p;
</code></pre>

{% endtab %}

{% tab title="C#" %}

```csharp
// If you want to have two threads
Nettention.Proud.ThreadPool p = new Nettention.Proud.ThreadPool(2);  
 
// ----------Forward the object to which this thread pool is registered as a parameter.----------
// For the server end
Nettention.Proud.StartServerParameter param = new Nettention.Proud.StartServerParameter();
param.SetExternalUserWorkerThreadPool(p);
 
// For the client end
Nettention.Proud.NetConnectionParam param = new Nettention.Proud.NetConnectionParam();
// Types of Thread Models in a ProudNet See also Open the link in a new window
param.userWorkerThreadModel = Nettention.Proud.ThreadModel.ThreadModel_UseExternalThreadPool;
param.SetExternalUserWorkerThreadPool(p);
```

{% endtab %}
{% endtabs %}

Setting up a thread pool is basically the same as above, with different values depending on your case.\
You can set up several thread models not only on servers but also on clients.

### - Multiple Network Modules Share the Same Thread Pool

<figure><img src="/files/Y476NI2S5iFIrqFx4w9R" alt=""><figcaption><p>Example of multiple host modules sharing the same Thread Pool on a server</p></figcaption></figure>

{% tabs %}
{% tab title="C++" %}

<pre class="language-cpp"><code class="lang-cpp">Proud::CStartServerParameter param1;
Proud::CStartServerParameter param2; 
Proud::CStartServerParameter param3; 
 
//Explicitly create a thread pool object with Proud::CThreadPool::Create()
<strong>Proud::CThreadPool* p = Proud::CThreadPool::Create(...);  
</strong>  
//Share the user worker thread pool
//The Networker thread pool is not shared, leaving the default settings in place.
param1.m_externalUserWorkerThreadPool = p;
param2.m_externalUserWorkerThreadPool = p;  
param3.m_externalUserWorkerThreadPool = p;
</code></pre>

{% endtab %}

{% tab title="C#" %}

```csharp
Nettention.Proud.StartServerParameter param1 = new Nettention.Proud.StartServerParameter();
Nettention.Proud.StartServerParameter param2 = new Nettention.Proud.StartServerParameter(); 
Nettention.Proud.StartServerParameter param3 = new Nettention.Proud.StartServerParameter();
 
Nettention.Proud.ThreadPool p = new Nettention.Proud.ThreadPool(2);  
  
//Share the user worker thread pool
//The Networker thread pool is not shared, leaving the default settings in place.
param1.SetExternalUserWorkerThreadPool(p);
param2.SetExternalUserWorkerThreadPool(p);  
param3.SetExternalUserWorkerThreadPool(p);
```

{% endtab %}
{% endtabs %}

### - Use different numbers of Networker and User worker thread pools

{% tabs %}
{% tab title="C++" %}

```cpp
Proud::CStartServerParameter param;
 
Proud::CThreadPool* p1 = Proud::CThreadPool::Create(..., 1); 
Proud::CThreadPool* p2 = Proud::CThreadPool::Create(..., 4);  
  
param.m_externalNetWorkerThreadPool = p1;  
param.m_externalUserWorkerThreadPool = p2;
```

{% endtab %}

{% tab title="C#" %}

```csharp
Nettention.Proud.StartServerParameter param = new Nettention.Proud.StartServerParameter();
 
Nettention.Proud.ThreadPool p1 = new Nettention.Proud.ThreadPool(1); 
Nettention.Proud.ThreadPool p2 = new Nettention.Proud.ThreadPool(4);  
  
param.SetExternalNetWorkerThreadPool(p1);  
param.SetExternalUserWorkerThreadPool(p2);
```

{% endtab %}
{% endtabs %}

### - Consolidate thread pool for Networker and User worker

{% tabs %}
{% tab title="C++" %}

```cpp
Proud::CStartServerParameter param;  
Proud::CThreadPool* p = Proud::CThreadPool::Create(..., 8); 
param.m_externalNetWorkerThreadPool = p;  
param.m_externalUserWorkerThreadPool = p;
```

{% endtab %}

{% tab title="C#" %}

```csharp
Nettention.Proud.StartServerParameter param = new Nettention.Proud.StartServerParameter();  
Nettention.Proud.ThreadPool p = new Nettention.Proud.ThreadPool(8); 
param.SetExternalNetWorkerThreadPool(p);  
param.SetExternalUserWorkerThreadPool(p);
```

{% endtab %}
{% endtabs %}

### - Pure single-threaded model

As a way to run a pure single-threaded server as many as the number of CPUs, you must create a thread pool object with no threads at all and manually continuously call a function that makes the thread pool breathe.

{% hint style="warning" %}
When specifying a Networker thread pool, do not call things like **Process** or **FrameMove** too slowly. The methods that are called should complete the necessary processing as quickly as possible.

Otherwise, you might get weird ping measurements internally, disconnections between server and client, etc.
{% endhint %}

{% tabs %}
{% tab title="C++" %}

```cpp
Proud::CStartServerParameter param;
Proud::CThreadPool* p = Proud::CThreadPool::Create(..., 0);  
 
param.m_externalNetWorkerThreadPool = p;  
param.m_externalUserWorkerThreadPool = p;  
....
 
void main()  
{  
    while(true)  
    {  
        // Wait up to 10 milliseconds to process events that have accumulated in the thread pool.  
        p->Process(10);  
    }  
}
```

{% endtab %}

{% tab title="C#" %}

```csharp
Nettention.Proud.StartServerParameter param = new Nettention.Proud.StartServerParameter();
Nettention.Proud.ThreadPool p = new Nettention.Proud.ThreadPool(0);  
 
param.SetExternalNetWorkerThreadPool(p);  
param.SetExternalUserWorkerThreadPool(p);  
....
 
static void Main(string[] args)  
{  
    while (true)  
    {  
        // Wait up to 10 milliseconds to process events that have accumulated in the thread pool.  
        p.Process(10);  
    }  
}
```

{% endtab %}
{% endtabs %}

## Setting up the Thread Model - Client

Above, we separated the user worker and networker to prevent mistakes from happening, but we still need to explicitly call FrameMove.\
This gives you the advantage of being able to run stacked RMI at any point in time.

Setting up a Thread Model is a way to ensure that you do not have to worry about complicated code on the client side, such as calling **Process** or **FrameMove**, causing logic to break or accidentally missing code.\
ProudNet provides a lot of manipulation over networking, but you can also set it up so that you do not care about it.

### - ProudNet Thread Model Types

> * <mark style="color:orange;">ThreadModel\_SingleThreaded</mark>: \
>   RMI and message callbacks complete when the user invokes FrameMove. (Default value)
> * <mark style="color:orange;">ThreadModel\_MultiThreaded</mark>: \
>   The callback completes immediately, even if the user does not invoke FrameMove.
> * <mark style="color:orange;">ThreadModel\_UseExternalThreadPool</mark>: \
>   When specifying a thread pool, you must set it to this.

You can set the above values in the <mark style="color:orange;">m\_netWorkerThreadModel</mark> and <mark style="color:orange;">m\_userWorkerThreadModel</mark> of the <mark style="color:orange;">CNetConnectionParam</mark>. The default value is <mark style="color:orange;">ThreadModel\_SingleThreaded</mark>.

{% tabs %}
{% tab title="C++" %}

<pre class="language-cpp"><code class="lang-cpp"><strong>Proud::CNetConnectionParam param;
</strong> 
//If you want to use custom thread pools for both user worker and network
param.m_userWorkerThreadModel = Proud::ThreadModel::ThreadModel_UseExternalThreadPool;  
param.m_netWorkerThreadModel = Proud::ThreadModel::ThreadModel_UseExternalThreadPool;  
 
//If you do not want to simply call FrameMove
param.m_userWorkerThreadModel = Proud::ThreadModel::ThreadModel_MultiThreaded;
</code></pre>

{% endtab %}

{% tab title="C#" %}

```csharp
Nettention.Proud.NetConnectionParam param = new Nettention.Proud.NetConnectionParam();
 
//If you want to use custom thread pools for both user worker and network
param.userWorkerThreadModel = Nettention.Proud.ThreadModel.ThreadModel_UseExternalThreadPool;  
param.netWorkerThreadModel = Nettention.Proud.ThreadModel.ThreadModel_UseExternalThreadPool;  
 
//If you do not want to simply call FrameMove
param.userWorkerThreadModel = Nettention.Proud.ThreadModel.ThreadModel_MultiThreaded;
```

{% endtab %}
{% endtabs %}

## Running user routines asynchronously

You can run your function or Lambda expression A asynchronously with <mark style="color:orange;">Proud.IRmiHost.RunAsync()</mark>.\ <mark style="color:orange;">Proud.IRmiHost.RunAsync()</mark> returns immediately, and A runs on one of the threads in the thread pool.

If you want A to run for host H with a given HostID, you guarantee that H's callback function and A will not run at the same time.

{% tabs %}
{% tab title="C++" %}

```cpp
Proud::CNetServer* s = ...;
Proud::HostID r1 = ...;
string a = ...;
 
s->RunAsync(r1, [a] { WriteSomething(a); });
```

{% endtab %}
{% endtabs %}

## Warnings for excessive sending volume

ProudNet's servers and network have the ability to detect and warn when the amount of sending is too much for the line speed. <mark style="color:orange;">Proud.INetCoreEvent.OnWarning</mark> with <mark style="color:orange;">ErrorType\_SendQueueIsHeavy</mark> is called.

If you are sending too much, we recommend refining unnecessary messaging or [**Throttling**](/proudnet.eng/proudnet/using_pn/communication-messages.md#throttling).


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.proudnet.com/proudnet.eng/proudnet/usage_pn/usage.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
