ProudNet.Cn
WebsiteProud ConsoleLanguage
  • 🌐ProudNet
    • ProudNet 簡介
    • 下載並安裝
      • ProudNet授權認證方法
      • AMI
    • 項目設定
      • C++
      • C#
      • Mac Xcode
      • Linux
      • Unity3D
        • iOS 建置
      • Unreal Engine 4
      • 運行 PIDL 編譯器
    • 使用 ProudNet
      • 伺服器和客戶端
        • 如何使用伺服器
        • 如何使用客戶端
      • RMI
        • 如何使用RMI
      • PIDL
        • 如何使用PIDL
      • 事件處理
      • 通訊訊息
      • P2P 通訊
        • 如何使用P2P通訊
    • 活用 ProudNet
      • 如何使用它
      • 性能小貼士
    • 在 ProudNet 中使用 DB
      • DB Cache System ver.2
        • DB Cache 理論和理解
        • DB Cache 安裝和網絡設置
        • DB Cache 伺服器和用戶端
        • DB Cache 使用與活用
          • DB Cache 活用法
      • ADO API
      • ODBC API
    • ProudNet 實用程式
  • ProudNet note
    • 技術說明
      • 對主循環的理解
      • 配置服務器防火牆
      • 加密和解密
      • 發生錯誤時的應對事項
      • 錯誤信息列表
      • 同步角色位置
      • 客戶端與服務器通信
      • MiniDump (Error Dump System)
      • [1.6 版本] 服務器間 LAN 通訊器
    • 詞彙表
    • Sample 例題
  • 🌐ProudChat
    • 介紹及使用指南
    • 下載 SDK
      • C++
      • C#
      • Unity3D
      • Unreal Engine 4
Powered by GitBook
On this page
  • 註冊和使用 Proxy & Stub 通信對象
  • 事件
  • - 客戶端與服務器通用
  • - 服務器
  1. ProudNet note
  2. 技術說明

客戶端與服務器通信

Previous同步角色位置NextMiniDump (Error Dump System)

Last updated 1 year ago

客戶端連接到服務器後,首先用TCP進行通信。

在此期間,如果通過後臺成功與服務器進行UDP孔穿孔,則可以進行UDP通信,但在此之前,reliable、全部被TCP代替。 但是自從UDP打孔成功以後,就被UDP代替了。

客戶端用各自的TCP端口、UDP端口進行通信,服務器用1個TCP listening port、1個以上的UDP端口進行通信,客戶端在保持與服務器TCP連接的同時,從服務器側的UDP端口中選擇一個。 即,服務器方均勻地共享給連接多個UDP port的所有客戶端。

例如,如果4萬個客戶端與打開2萬個UDP port的服務器進行通信,服務器方面的每個UDP port就有2個客戶端進行通信。

註冊和使用 Proxy & Stub 通信對象

我們將通信添加到服務器和客戶端。 爲了方便起見,在創建服務器和客戶端都使用的Common(公用)方案後,準備PIDL文件。 定義從服務器向客戶端發送通信的協議,用於準備好的PIDL文件。

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

編譯上述PIDL文件時,生成Proxy和Stub客體。

如何使用 Proxy 對象

請先將Header包含在您要使用的地方。

// Server: 通過Server ▶ Client 
// Server爲了進行呼叫 
// 包含 Proxy 對象。
// header file 宣言
// 創建Common項目
// 因爲假設了Common 方案的 
// 包含從文件夾創建的文件 。
#include "../Common/S2C_proxy.h"
  
// 在 cpp 文件中聲明
#include "../Common/S2C_proxy.cpp"

創建Proxy並註冊爲服務器對象。

// 創建對象。
S2C::Proxy g_S2CProxy;
  
void main()
{
    // 在 Server 描述中創建的 
    // Server 對象。
    CNetServer* srv = 
         ProudNet::CreateServer();
    Svr->AttachProxy(&g_S2CProxy);
  
    // 以下省略
}

使用AttachProxy函數,以移交生成的Proxy客體的指針的方式進行註冊。 AttachProxy通過內部排列管理,可以註冊多種PIDL。 如果註冊了,可以使用Proxy客體的函數進行通信。

// HostID 和 RmiContext 
// 會自動添加。
// 想要發送到hostID的 
// 輸入 Client 的 HostID 值 。
g_S2CProxy.Chat(
         hostID, 
         RmiContext::ReliableSend, 
         “Send Message”);

與 Proxy 一樣,stub 也會在要使用的地方包含 Header。

Client:
 Server ▶ Client,在Client中 
 包含 Stub 對象以接收呼叫 。
// header file 宣言
// 創建Common項目 
// 因爲假定, 所以在Common文件夾中 
// 包含創建的文件 。
#include "../Common/S2C_stub.h"
  
// 在 cpp 文件中聲明
#include "../Common/S2C_stub.cpp"

對於Stub客體,因爲是接收協議的定義函數,所以必須生成並使用繼承的對象。 使用AttachStub函數註冊後,相應呼叫到來時會回電。 生成的Stub客體內會產生定義(Define),如果使用它,即使變更協議,也不需要另外修改cpp文件和h文件。

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

在 Stub Class 中指定的 Define 語句中, DEFRMI_NameSpace_函數名稱在繼承對象的 Header 文件中聲明, DECRMI_NameSpace_函數名稱 (Class_Name) 在 cpp 中聲明。

class CS2CStub : public S2C::Stub
{
public:
  
// 即使變更Protocol,用戶 
// 無需修改class,在stub內 
// 已處理爲define文。
// 以" DEFRMI_NameSpace_ 函數名" 
// 如果有, 在header 中聲明 。
    DECRMI_S2C_Chat;
};
CS2CStub g_S2CStub;
  
// 'DEFRMI_Protocol分類名_protocol名(
//               繼承的類 name'
// 如果設置爲 , 則在 cpp 中聲明 。
DEFRMI_S2C_Chat(CS2CStub)
{
    printf( 
         "[Client] HostID:%d, text: %s”, 
         remote, 
         txt);
  
         // 必須回傳 true
    return true;
}

'True' Return意味着已經處理完畢。 如果Return'False',則判斷爲用戶未對協議進行處理,OnNoRmiProcessed Event將返現。 在返回DEFRMI_S2C_Chat的函數因子中,remote是調用RMI的相對HostID值。 使用此ID值調用Proxy,可以將通信發送給您想要的對方。

現在將生成的Stub客體註冊到Client客體。

CNetClient *client 
         = ProudNet:CreateClient();
client->AttachStub(&g_S2CStub);
// 以下省略

AttachStub函數也在內部進行排列管理,以移交指針的方式進行註冊。

如何使用 Proxy 對象

生成PIDL編譯結果中包含的Proxy、Stub等類。

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

創建 Proxy,然後在 Client 上 attach Proxy。

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

如何使用 Stub 對象

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

和Proxy一樣,在stub上也使用的地方生成Stub,並在Client上attach。

與c++版本不同,DotNet版本中Stub爲delegate。

// 設置要處理Stub的delegate。
s2cStub.NotifyLocalHeroViewersGroupID = NotifyLocalHeroViewersGroupID; //<- 設置以下函數。
//同樣創建並配置下面的函數。
s2cStub.RemoteHero_Appear = RemoteHero_Appear;

s2cStub.RemoteHero_Disappear = RemoteHero_Disappear;

c2cStub.P2P_LocalHero_Move = P2P_LocalHero_Move;


...

netClient.AttachStub(s2cStub);

netClient.AttachStub(c2cStub);

...


//根據delegate創建函數。
bool NotifyLocalHeroViewersGroupID(Nettention.Proud.HostID remote, Nettention.Proud.RmiContext rmiContext, Nettention.Proud.HostID localHeroViewersGroupID)
{
    ...
    return true;
}

初始化Nettention.Proud.NetConnectionParam並呼叫Nettention.Proud.NetClient.Connect()。 調用並連接到伺服器。

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

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

//設置要連接的端口。
param.serverPort = 32222;

//設置要連接的IP地址。
param.serverIP = serverAddr;

netClient.Connect(param);

開發後必須檢查流量。 通信量需要在各客戶端、(如果使用Super peer功能,在Super Peer)服務器等分別檢查通信量,消除不必要的通信量。 爲了確認流量,請參考以下方法。

  • 使用 NetLimiter 等工具 。

  • 有一種方法是,準確執行每臺電腦使用的程序個數後,確認作業管理者間隔的收發字節數。

  • 使用ProudNet的內部函數CNetServer::GetStats(CNetServerStats &outVal); 實時獲取每秒收發的流量、發送或接收的數量等。 如果一個客戶端的總流量超過20~30KB,海外服務可能會出現問題。

我建議您使用後刪除NetLimiter等工具。 因Kernel Hooking功能,給握住通信設備的核心帶來20倍以上原本速度的負擔。

事件

- 客戶端與服務器通用

使用參數errorInfo的errorInfo-> ToString();可輕鬆獲得有關問題的信息。

事件
註釋

OnError

ProudNet內部發生的Error或因使用過程中出現問題而反饋信息。

OnWarnning

對不嚴重但存在潛在問題的信息進行回電。

OnInformation

對內部情況及溯源等信息進行回電。

OnException

回撥內部Exception錯誤信息。

OnNoRmiProcessed

向PIDL宣佈,但Stub未繼承Event或用戶Return false時呼叫。

- 服務器

可用於性能測試等。

事件
註釋

OnUserWorkerThreadBegin

User Worker Thread Pool 的 Thread 啓動時被調用 。

OnUserWorkerThreadEnd

User Worker Thread Pool 的 Thread 結束時被調用 。

Unreliable 信息
Reliable 信息