# 如何使用客戶端

## 定時器循環、RMI、事件處理

根據[**客戶端的主循環**](https://docs.proudnet.com/proudnet.cn/proudnet-note/notes/main_loop#undefined)，客戶端可以定期呼叫<mark style="color:orange;">FrameMove</mark>來執行累積的RMI接收並處理事件處理。

您不一定要每秒調用<mark style="color:orange;">FrameMove</mark>，但如果太長時間不調用，從客戶端接收到的RMI就會累積並增加記憶體使用量。

## 獲取各種資訊

客戶端可以檢索各種訊息，例如P2P群組資訊、P2P連線的客戶端的IP資訊、與伺服器的連線狀態以及是否正在與P2P連線的客戶端執行P2P中繼。

<table data-full-width="true"><thead><tr><th width="342">C++ 函數</th><th width="343">C# 函數</th><th>註釋</th></tr></thead><tbody><tr><td>Proud.CNetClient.GetGroupMembers</td><td>Nettention.Proud.NetClient.NativeNetClient.GetGroupMembers</td><td>檢索與作為參數給出的 HostID 對應的群組中的所有使用者。</td></tr><tr><td>Proud.CNetClient.GetIndirectServerTimeMs</td><td>Nettention.Proud.NetClient.NativeNetClient.GetIndirectServerTimeMs</td><td>取得以 HostID 為參數輸入的對等方的伺服器時間。</td></tr><tr><td>Proud.CNetClient.GetLastUnreliablePingMs</td><td>Nettention.Proud.NetClient.GetLastUnreliablePingMs</td><td>取得以 HostID 為參數輸入的對等方的最後 ping 時間。</td></tr><tr><td>Proud.CNetClient.GetLocalHostID</td><td>Nettention.Proud.NetClient.GetLocalHostID</td><td>取得客戶端的本機 HostID。</td></tr><tr><td>Proud.CNetClient.GetLocalJoinedP2PGroups</td><td>Nettention.Proud.NetClient.GetLocalJoinedP2PGroups</td><td>取得所有加入的 p2p 群組的清單。</td></tr><tr><td>Proud.CNetClient.GetP2PServerTimeMs</td><td>Nettention.Proud.NetClient.NativeNetClient.GetP2PServerTimeMs</td><td>取得 p2p 連線伺服器的時間（以毫秒為單位）。</td></tr><tr><td>Proud.CNetClient.GetPeerInfo</td><td>Nettention.Proud.NetClient.GetPeerInfo</td><td>取得有關連接到客戶端的對等點的資訊。</td></tr><tr><td>Proud.CNetClient.GetPeerReliableUdpStats</td><td>Nettention.Proud.NetClient.NativeNetClient.GetPeerReliableUdpStats</td><td>取得 P2P 之間可靠的訊息系統運行統計資料。 （用於效能測量或調試）</td></tr><tr><td>Proud.CNetClient.GetRecentUnreliablePingMs</td><td>Nettention.Proud.NetClient.GetRecentUnreliablePingMs</td><td>傳回最近的 ping 時間（以毫秒為單位）。</td></tr><tr><td>Proud.CNetClient.GetServerAddrPort</td><td>Nettention.Proud.NetClient.NativeNetClient.GetServerAddrPort</td><td>取得連接的伺服器的位址。</td></tr><tr><td>Proud.CNetClient.GetServerConnectionState</td><td>Nettention.Proud.NetClient.GetServerConnectionState</td><td>取得與伺服器的套接字連線的狀態。</td></tr><tr><td>Proud.CNetClient.GetServerTimeMs</td><td>Nettention.Proud.NetClient.NativeNetClient.GetServerTimeMs</td><td>取得伺服器上的當前時間。</td></tr><tr><td>Proud.CNetClient.GetServerTimeDiffMs</td><td>Nettention.Proud.NetClient.NativeNetClient.GetServerTimeDiffMs</td><td>找出客戶端和伺服器之間的時間差。</td></tr></tbody></table>

## 伺服器連接期間發送和接收自訂數據

* 當您在 <mark style="color:orange;">Connect</mark> 中填寫自訂欄位參數時，\
  內容是從 <mark style="color:orange;">OnConnectionRequest</mark> 接收的。
* 如果在<mark style="color:orange;">OnConnectionRequest</mark>中填入自訂回覆參數，\
  內容是從 <mark style="color:orange;">OnJoinServerComplete</mark> 接收的。

<figure><img src="https://content.gitbook.com/content/hhO5qj4oN2uLfVC5EG5W/blobs/B7aZqTfVPS2x5D5xCnHL/client_connect_server.png" alt=""><figcaption><p>使用 C++ 解釋客戶端到伺服器連線過程的範例</p></figcaption></figure>

## 取得打孔地址

1. 首先，完成P2P通訊。
2. 使用 <mark style="color:orange;">GetPeerInfo</mark> 或 <mark style="color:orange;">GetClientInfo</mark> 取得客戶端資訊。
3. 取得到的資訊中的<mark style="color:orange;">udpAddrFromServer</mark>為打洞位址。

{% hint style="success" %}
**參考**\
[**P2P 通訊**](https://docs.proudnet.com/proudnet.cn/proudnet/using_pn/p2p)
{% endhint %}

## 取得伺服器時間

ProudNet可讓您從伺服器取得時間以實現主機之間的時間同步。

<table data-full-width="true"><thead><tr><th width="348">C++ 函數</th><th>C# 函數</th><th>註釋</th></tr></thead><tbody><tr><td>Proud.CNetClient.GetServerTimeMs</td><td>Nettention.Proud.NetClient.GetServerTimeMs</td><td>與伺服器計算延遲以獲得伺服器的實際時間。</td></tr><tr><td>Proud.CNetClient.GetP2PServerTimeMs</td><td>Nettention.Proud.NativeNetClient.GetP2PServerTimeMs</td><td>一種取得伺服器延遲、計算其他 P2P 連線客戶端延遲並取平均值的方法。 更準確地說，您可以獲得伺服器上的實際時間。</td></tr></tbody></table>

## 回呼中途斷開

當呼叫 <mark style="color:orange;">FrameMove</mark> 時，將立即呼叫所有累積的事件和接收到的 RMI。

如果使用者願意，ProudNet 能夠在單一 <mark style="color:orange;">FrameMove</mark> 呼叫部分的處理過程中傳回累積事件和接收到的 RMI。 然後，它允許在下一個 <mark style="color:orange;">FrameMove</mark> 呼叫中處理剩餘的累積事件和接收到的 RMI。

\
若要終止剩餘的累積事件和接收的 RMI，請從正在處理 RMI 接收的例程或正在處理事件接收的例程呼叫 <mark style="color:orange;">HolsterMoreCallbackUntilNextFrameMove</mark>。

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

```cpp
DEFRMI_TestS2C_Foo(CMyClient)
{
    ...
    /* 當您呼叫此函數時，CNetClient.FrameMove 立即傳回，
    忽略任何剩餘的累積事件和 RMI 接收。 */
    m_netClient->HolsterMoreCallbackUntilNextFrameMove();
}
 
void CMyClient::OnLeaveServer(...)
{
    ...
    /* 當您呼叫此函數時，CNetClient.FrameMove 立即傳回，
    忽略任何剩餘的累積事件和 RMI 接收。 */
    m_netClient->HolsterMoreCallbackUntilNextFrameMove();
}
```

{% endtab %}

{% tab title="C#" %}

```csharp
simpleStub.Test = (remote, rmiContext, text) => {
    ...
    /* 當您呼叫此函數時，CNetClient.FrameMove 立即傳回，
    忽略任何剩餘的累積事件和 RMI 接收。 */
    netClient.HolsterMoreCallbackUntilNextFrameMove();
}

netClient.LeaveServerHandler = (errInfo) => {
    ...
    /* 當您呼叫此函數時，CNetClient.FrameMove 立即傳回，
    忽略任何剩餘的累積事件和 RMI 接收。 */
    netClient.HolsterMoreCallbackUntilNextFrameMove();
}

```

{% endtab %}
{% endtabs %}

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

[**理解主循環**](https://docs.proudnet.com/proudnet.cn/proudnet-note/notes/main_loop)
{% endhint %}

<details>

<summary>保留回呼</summary>

當各種事件和RMI接收被<mark style="color:orange;">FrameMove</mark>回調時，有一個函數允許稍後再次發生所需的回調，稱為**保留回呼**。\
如果您暫停回調，則待處理的回呼將轉到累積接收佇列的後面，並且下次呼叫 <mark style="color:orange;">FrameMove</mark> 時回呼會再次發生。

例如，如果您按住Callback B，則回調將執行如下所示。

FrameMove => Callback A => Callback B (保留!) => 返回

FrameMove => Callback B(回放被擱置的內容) => ... => 返回

如果這個回呼函數沒有被準確理解和誤用，可能會被誤解為接收到的RMI或事件沒有按正確的順序到達或發生無限回呼。 因此，使用時需謹慎。

若要掛起回調，只需從處理 RMI 接收的程式或處理事件接收的例程中呼叫 <mark style="color:orange;">Proud.INetClientEvent.PostponeThisCallback</mark> 或 <mark style="color:orange;">Proud.IRmiStub.PostponeThisCallback</mark> 即可。

```cpp
DEFRMI_TestS2C_Foo(CMyClient)
{
    ...
    /* 當您呼叫此函數時，CNetClient.FrameMove 立即傳回，
    忽略任何剩餘的累積事件和 RMI 接收。 */
    PostponeThisCallback();
}
 
void CMyClient::OnLeaveServer(...)
{
    ...
    /* 當您呼叫此函數時，CNetClient.FrameMove 立即傳回，
    忽略任何剩餘的累積事件和 RMI 接收。 */
    PostponeThisCallback();
}
```

</details>

***

## :arrow\_left: [**返回**](https://docs.proudnet.com/proudnet.cn/proudnet/using_pn/server_client)
