# 活用 ProudNet

## ProudNet 伺服器

ProudNet 伺服器是 <mark style="color:orange;">Proud::CNetServer</mark> 實例，具有以下角色。\
另外，它還作爲P2P通信的relay服務器發揮着作用。

> * 接受並管理來自 ProudNet 用戶端的連接
> * 與客戶端進行通訊：RMI
> * 客戶端間P2P通訊的群組管理：參考[**P2P群組**](/proudnet.cn/proudnet/using_pn/p2p.md#p2p)

## ProudNet 客戶端

ProudNet 網路用戶端是 <mark style="color:orange;">Proud::CNetClient</mark> 實例，具有以下角色。

> * 與伺服器連線/中斷連線：請參閱[**從客戶端連線到伺服器**](/proudnet.cn/proudnet/using_pn/server_client.md#undefined-10)
> * 與伺服器通訊：RMI
> * 與其他客戶端的P2P通訊：RMI

<figure><img src="/files/yN06hgqknzEmx0EO9PHn" alt=""><figcaption><p>Client Server</p></figcaption></figure>

## ProudNet 協定類型

支援的訊息傳遞協定如下，您可以選擇一種並將其輸入為 RMI 函數呼叫中的參數。

<table><thead><tr><th width="217">協定類型</th><th>註釋</th></tr></thead><tbody><tr><td>Reliable messaging</td><td>雖然主機間收發信息的時間比unreliable長，但收發順序和到達是保證的。</td></tr><tr><td>Unreliable messaging</td><td>雖然主機間收發消息的時間比reliable短，但收發順序可能會不順，無法保證到達。</td></tr></tbody></table>

<mark style="color:orange;">Client</mark> 和 <mark style="color:orange;">Server</mark> 使用的通信協議

<table data-full-width="true"><thead><tr><th width="252">狀態</th><th width="283">Reliable P2P RMI</th><th width="191">Unreliable P2P RMI</th><th>Reliable C-S RMI</th><th>Unreliable C-S RMI</th></tr></thead><tbody><tr><td>正常</td><td>Reliable UDP</td><td>UDP</td><td>TCP</td><td>UDP</td></tr><tr><td>對等點之間的 UDP 通訊不良</td><td>Relay and Reliable UDP or TCP</td><td>Relay and TCP</td><td>TCP</td><td>UDP</td></tr><tr><td>雲端與伺服器之間的 UDP 通訊不良</td><td>Relay and TCP</td><td>Relay and TCP</td><td>TCP</td><td>TCP</td></tr></tbody></table>

{% hint style="info" %}

* <mark style="color:orange;">Reliable UDP</mark>是ProudNet自身實現功能。
* Relay由<mark style="color:orange;">Server</mark>負責。
  {% endhint %}

{% hint style="success" %}
**協議選擇技巧**\
第一次開發遊戲時，使用<mark style="color:orange;">Proud.RmiContext.ReliableSend</mark>將所有信息發送到<mark style="color:orange;">Reliable messaging</mark>。 然後參考訪問所有RMI呼叫時間，收集RMI消息收發明細。

一般來說,在遊戲程序中,20%以下的RMI信息種類佔全部收發量的80%以上,其中發送頻率非常高,即使發生20%以下的流失,也會找到沒有什麼問題的RMI,修改爲使用<mark style="color:orange;">Unreliable messaging</mark>。
{% endhint %}

## ProudNet客戶端-服務器通信

在ProudNet中，客戶端和服務器之間的通信以信息爲單位構成，每個信息對應1次RMI呼叫，reliable、unreliable通信均可進行。

{% hint style="success" %}
**參考**

[**RMI** ](/proudnet.cn/proudnet-note/dictionary.md#rmi)

[**伺服器-客戶端 通信** ](/proudnet.cn/proudnet-note/notes/client_server_communication.md)
{% endhint %}

## ProudNet P2P通訊效能

ProudNet擁有超越普遍化的打孔及接力技術的功能,非常強大,支持沒有連接等待時間的TCP等P2PReliable信息。\
由於對敏感或有缺陷的NAT裝置具有抗性,因此可以自行解決低速網絡超負荷的P2P發送量,用戶要求連接P2P通信(<mark style="color:orange;">Proud.CNetServerCreateP2PGroup</mark>或<mark style="color:orange;">Proud.CNetServer.JoinP2PGroup</mark>)後,立即執行客戶端之間的信息。

部分NAT設備因對同一內部地址的外部地址映射管理不當而丟失,ProudNet在客戶端之間設有不同的UDP socket,只在必要的情況下嘗試打孔,最大限度地減少這種映射信息的丟失。

例如，如果已連接P2P，但未進行真正的P2P通信，則不進行打孔。 因此,在調用<mark style="color:orange;">Proud.CNetServer.CreateP2PGroup</mark> , <mark style="color:orange;">Proud.CNetServer.JoinP2PGroup</mark>後,仍然調用<mark style="color:orange;">Proud.RmiContext.m\_relayed</mark>, <mark style="color:orange;">Proud.CNetClientInfo.m\_RelayedP2P</mark>, <mark style="color:orange;">Proud.CNetPeerInfo.m\_RelayedP2P</mark> 值是 false， 但一旦您開始使用 P2P 通信， 將會更改爲 true 。

即使在上傳速度比下載速度慢的家用電腦（例如ADSL或ADSL2+）上打孔，也可能無法克服傳輸量，且發送端的發送電腦或NAT裝置可能無法正常運作。

此時，ProudNet使用內建的解析功能來偵測多播客戶端的過度傳輸，並將多播分發到中繼伺服器。

「連接埠預測技術」稱為 NAT 打洞策略。\
該技術允許在symmetricNAT設備之間進行孔穿孔，但存在由於端口映射過多而產生的不良影響。\
為了最大限度地減少副作用，ProudNet 最初避免過度打孔，然後逐漸轉向連接埠預測等激進方法。 因此，在某些NAT設備中，將路由切換到直接P2P需要一段時間，但這不是問題，因為它先使用打洞，然後使用中繼技術。

{% hint style="success" %}
**參考**

[**打孔 (Hole Punching)**](/proudnet.cn/proudnet-note/dictionary.md#hole-punching)

[**P2P 通訊**](/proudnet.cn/proudnet/using_pn/p2p.md)
{% endhint %}

## ProudNet的UDP通訊相關效能

ProudNet在使用UDP協議時,爲了提高通信性能,採用<mark style="color:orange;">Coalesce</mark>, <mark style="color:orange;">MTU discovery fail</mark>預防等方法。

在小容量通訊（例如延遲小於 1 毫秒的 LAN 環境）中，通訊負載似乎大於實際 RMI 資料容量。 然而，在通訊量增加或延遲較高的 WAN 環境中，與 LAN 中的少量通訊相比，通訊負載會降低。

<figure><img src="/files/wqln1BBIXo7pjoSgaUUA" alt=""><figcaption><p>隨著RMI調用次數增加的通訊量關係</p></figcaption></figure>

在相距100公里以上的互聯網通信中，需要經過大量機型的Gateway設備的分組。\
每個網關都指定了不同的可承受MTU大小，但當發送方超過定義的MTU大小時，就會發生ICMP分組分組。

一些用戶由於害怕ICMP攻擊而設置屏蔽所有類型的ICMP分組,在這種情況下,由於無法處理ICMP分組分組,MTU discovery失敗,最終導致兩個主機之間的UDP通信中斷。

ProudNet 具有防止這種情況發生的功能。

## ProudNet 上的加密通信

ProudNet的加密通訊協定非常強大。

需要加密的訊息使用<mark style="color:orange;">對稱金鑰</mark>進行加密，此時使用的<mark style="color:orange;">對稱金鑰</mark>使用<mark style="color:orange;">公鑰</mark>進行加密並在主機之間進行交換。 這些加密金鑰無法被第三方破解，因為它們不僅在伺服器和用戶端中，而且在客戶端之間的 P2P 通訊中都被分配了唯一的值。

此外，加密訊息的內部內容每次傳輸到另一台主機時都會發生顯著變化，從而防止駭客在捕獲資料包後重新傳輸相同或相似訊息的嘗試。 但是，它的處理速度比非加密訊息傳遞要低，因此請謹慎使用。

ProudNet 使用 128 位元 RSA 作為非對稱金鑰演算法，使用 AES 或 Fast 作為<mark style="color:orange;">對稱金鑰</mark>演算法。 由於單獨使用RSA需要太多的計算量，因此將其與<mark style="color:orange;">對稱金鑰</mark>演算法結合使用。

它不僅為客戶端和伺服器之間的通訊提供了加密功能，還為P2P通訊提供了加密功能，提供了出色的安全性。 此外，RMI中使用的<mark style="color:orange;">對稱金鑰</mark>是高度可靠的，因為它是在初始伺服器連線時使用RSA演算法<mark style="color:orange;">公鑰</mark>加密後進行交換的。

<figure><img src="/files/m2gKMiUk0f1PGbl60dlh" alt=""><figcaption></figcaption></figure>

&#x20;

{% hint style="danger" %}
ProudNet 用戶端連線到伺服器時發生的 <mark style="color:orange;">Proud::INetServerEvent::OnConnectionRequest</mark> 事件中的自訂欄位未加密。 請不要透過此方式傳遞您的訊息。
{% endhint %}

### - ProudNet加密技術

ProudNet 根據效能和安全性等級提供各種加密功能。\
若要傳送加密訊息，請呼叫 RMI 方法或在 <mark style="color:orange;">SendUserMessage</mark> 系列方法中輸入的參數中的 <mark style="color:orange;">Proud.RmiContext.m\_encryptMode</mark> 中選擇所需的加密方法。

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

```cpp
Proud::RmiContext rmiContext;
rmiContext.m_encryptMode = Proud::EncryptMode::EM_Secure;
// proxy 函數示例
Proxy.RequestLogon(Proud::HostID::HostID_Server, rmiContext, m_Name, password);
```

```cpp
Proud::RmiContext rmiContext;
rmiContext.m_encryptMode = Proud::EncryptMode::EM_Fast;
Proxy.RequestLogon(Proud::HostID::HostID_Server, rmiContext, m_Name, password);
```

或者您可以像這樣輕鬆地使用它。

```cpp
Proxy.RequestLogon(Proud::HostID::HostID_Server,Proud::RmiContext::SecureReliableSend, m_Name, password); 
// 使用 EM_Secure
```

```cpp
Proxy.RequestLogon(Proud::HostID::HostID_Server,Proud::RmiContext::FastEncryptedReliableSend, m_Name, password); 
// 使用 EM_Fast
```

{% endtab %}

{% tab title="C#" %}

<pre class="language-csharp"><code class="lang-csharp"><strong>Nettention.Proud.RmiContext rmiContext;
</strong>rmiContext.encryptMode = Nettention.Proud.EncryptMode.EM_Secure;
// proxy 函數示例
Proxy.RequestLogon(Nettention.Proud.HostID.HostID_Server, rmiContext, name, password);
</code></pre>

```csharp
Nettention.Proud.RmiContext rmiContext;
rmiContext.encryptMode = Nettention.Proud.EncryptMode.EM_Fast;
Proxy.RequestLogon(Nettention.Proud.HostID.HostID_Server, rmiContext, name, password);
```

```csharp
Proxy.RequestLogon(Nettention.Proud.HostID.HostID_Server,Nettention.Proud.RmiContext.SecureReliableSend, name, password); 
// 使用 EM_Secure
```

```csharp
Proxy.RequestLogon(Nettention.Proud.HostID.HostID_Server,Nettention.Proud.RmiContext.FastEncryptedReliableSend, name, password); 
// 使用 EM_Fast
```

{% endtab %}
{% endtabs %}

{% hint style="warning" %}
在P2P群組中使用加密功能時  <mark style="color:orange;">CStartServerParameterBase::m\_enableP2PEncryptedMessaging</mark> 的值必須設為 **true**。

在 C# 中，您可以使用 <mark style="color:orange;">StarSeverParameterBase.enableP2PEncryptedMessaging</mark>。
{% endhint %}

### - 加密金鑰長度：加密等級和效能之間的平衡

ProudNet 的加密過程涉及主機之間的內部金鑰交換。 此時，使用者可以設定交換和接收的金鑰長度，設定時必須考慮系統的效能和加密等級。<br>

加密金鑰的長度可以在啟動伺服器時在參數 <mark style="color:orange;">Proud.CStartServerParameter.m\_encryptedMessageKeyLength</mark> 和 <mark style="color:orange;">Proud.CStartServerParameter.m\_fastEncryptedMessageKeyLength</mark> 中設定。

> * <mark style="color:orange;">Proud.CStartServerParameter.m\_encryptedMessageKeyLength</mark> 參數
>
> 這是指使用 AES 加密時金鑰的長度，您可以設定 <mark style="color:orange;">Proud.EncryptLevel.EncryptLevel\_Low</mark>、<mark style="color:orange;">Proud.EncryptLevel.EncryptLevel\_Middle</mark> 和 <mark style="color:orange;">Proud.EncryptLevel.EncryptLevel\_High</mark> 的金鑰長度。
>
> &#x20;
>
> * <mark style="color:orange;">Proud.CStartServerParameter.m\_fastEncryptedMessageKeyLength</mark> 參數
>
> 指的是使用快速加密時的金鑰長度，可以設定<mark style="color:orange;">Proud.FastEncryptLevel.FastEncryptLevel\_Low</mark>、<mark style="color:orange;">Proud.FastEncryptLevel.FastEncryptLevel\_Middle</mark> 和 <mark style="color:orange;">Proud.FastEncryptLevel.FastEncryptLevel\_High</mark>的金鑰長度。

AES 加密比 Fast 稍慢，但提供高品質的加密。

然而，對於不重要的數據，例如角色移動訊息，或需要大量發送和接收的訊息，您可以使用Fast，因為它的效能很快。

### - ProudNet的Fast AES演算法性能比較

下面是ProudNet的Fast AES演算法的效能比較。 測量了執行 100,000 次加密和解密（每次一次）所需的時間。

<figure><img src="/files/k1Tw4Phlu6vmHW1TEqqC" alt=""><figcaption><p>ProudNet Fast AES演算法效能對比</p></figcaption></figure>

**測試規格**

<table><thead><tr><th width="175" align="center">項目</th><th>規格</th></tr></thead><tbody><tr><td align="center">OS</td><td>Windows 7 Professional K</td></tr><tr><td align="center">CPU</td><td>Intel(R) Core(TM) i7-3770 CPU @ 3.40GHz 3.40GHz</td></tr><tr><td align="center">RAM</td><td>16.0GB</td></tr><tr><td align="center">System type</td><td>64-bit Operating System</td></tr></tbody></table>

{% hint style="success" %}
**參考**

[**加密與解密**](/proudnet.cn/proudnet-note/notes/encryption_decoding.md)
{% endhint %}

## ProudNet 訊息壓縮功能

ProudNet允許對訊息進行壓縮和傳輸，並且透過使用主機的CPU來減少通訊量，從而提高效率。 若要壓縮訊息，請呼叫 RMI 方法或在呼叫 <mark style="color:orange;">SendUserMessage</mark> 方法時將參數 <mark style="color:orange;">Proud.RmiContext.m\_compressMode</mark> 設定為 <mark style="color:orange;">Proud.CM\_None</mark> 以外的值。

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

```cpp
Proud::RmiContext rmi = Proud::RmiContext::ReliableSend;
rmi.m_compressMode = Proud::CompressMode::CM_Zip;
 
Proxy.SendFileChunk(Proud::HostID::HostID_Server, rmi, dataBlock);
```

{% endtab %}

{% tab title="C#" %}

```csharp
Nettention.Proud.RmiContext rmi = Nettention.Proud.RmiContext.ReliableSend;
rmi.compressMode = Nettention.Proud.CompressMode.CM_Zip;
 
Proxy.SendFileChunk(Nettention.Proud.HostID.HostID_Server, rmi, dataBlock);
```

{% endtab %}
{% endtabs %}


---

# 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.cn/proudnet/usage_pn.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.
