2012-07-10 47 views
1

我正在C#中創建一個服務器,我有一個單例處理數組中的所有登錄用戶。該數組是一個名爲UserSession的類的數組。在類內處理幾個方法的最佳方法?

此UserSession類具有一個方法,該方法在處理該用戶的傳入數據包的單獨線程上運行。

好,考慮下面的代碼:

class UserSession 
{ 
    public UserSession(TcpClient client) 
    { 
     var thread = new Thread(new ParameterizedThreadStart(HandleComm); 
     thread.Start((object)client); 
    } 

    public void HandleComm(object tcpClient) 
    { 
     TcpClient client = (TcpClient)tcpClient; 
     NetworkStream stream = client.GetStream(); 
     while(1 == 1) 
     { 
      byte[] buffer = new byte[4096]; 
      stream.Read(buffer, 0, buffer.Length); 
      int testShort = Convert.ToInt32(buffer); 
      switch((ActionEnum)testShort) 
      { 
       case ActionEnum.Something: 
        // here is my problem! 
        // do some more parsing of the message 
        this.DoSomething(SomethingStruct argument); // argument taken from the byte array 
        break; 
       case ActionEnum.AnotherSomething: 
        // the same as before 
        break; 
       // and this goes on and on 
      } 
     } 
    } 
} 

什麼是處理所有這些不同的枚舉而無需重複的超過80種方法對班上最好的方法是什麼? (ActionEnum是具有當前用戶特定操作的枚舉)。

我序列化該緩衝區,我只是快速讓你有一個想法的代碼。

+1

鏈如何出現在你的類'UserSession'是單身?它有一個公共構造函數 – Habib 2012-07-10 04:24:36

+0

我希望你處理任何stream.Read()返回你的生產代碼。至於這個問題,有很多方法有什麼問題?如果你只做了幾行代碼,處理可能會停留在案例本身;否則它可能值得一種方法。 upd:如果你的對象是一致的序列化的,它實際上可能是一個方法,其中一些描述傳入消息的格式作爲參數。 – 2012-07-10 04:28:38

+0

@ Habib.OSU我在一個名爲LoggedUsers的類裏面有一個UserSession數組,這是一個單身人士 – Pacha 2012-07-10 04:31:23

回答

1

一如既往有很多可能的答案。當我構建我的客戶端/服務器遊戲時,我遇到了這個問題。我開始與幾十個行動/事件/消息枚舉,然後意識到它不是非常可持續的,當你進入更多的行動。

所以這就是我在粗略的僞代碼中所做的。

NetworkClass 
    { 
     RegisterChannel(objUsingChannel,typeOfChannel, callbackForChannel, expectedReturnType){/*...*/}; 

     PushChannelMsg(channelID, dataToSend) 

     ReceiveMessageFromNetwork(msg){ Read data from network, which also contains channelID, and send it to any matching channelID} 
     //If there is no channel registered for a data that is received, just ignore it 
    } 

EnemyTurretObject 
{ 
    //Register the rotation channel and listen for rotation changes 
    NetworkClass.RegisterChannel(this, channels.TurretRotated + this.ID, callback=HandleTurretRotated, doubleReturnType) 

    HandleTurretRotated(double rot) 
    { rotate the turret } 
} 

FriendlyTurretObject 
{ 
    //Register two channels that we'll send data across 
    NetworkClass.RegisterChannel(this, channels.TurretFired + this.ID, callback=null, MissleFiredData) 
    NetworkClass.RegisterChannel(this, channels.TurretRotated + this.ID, callback=null, doubleDataType) 

    FireMissle() 
    { 
     NetworkClass.PushChannelMsg(channels.TurretFired + this.ID, new MissleFiredData(x,y)) 
    } 

    RotateTurret() 
    { 
     NetworkClass.PushChannelMsg(channels.TurretRotated + this.ID, newTurretRotationValue) 
    } 

} 

我基本上避免枚舉整個巨大腫塊,並提出了更廣義的設置,使每個對象負責它自己的數據,渠道等。這是更靈活的方法,更改一個枚舉不會破壞所有內容。網絡類甚至不需要知道正在發送的數據是什麼,現在它只是一個管道。

+0

當你收到用戶的數據包時你會怎麼做?假設你有不同的行爲,比如「連接」或「斷開連接」。你有很多不同的連接嗎? – Pacha 2012-07-10 04:50:44

+0

更具體地處理連接和斷開連接。這些類型的案例不一定要在我上面描述的消息傳遞系統中。是的,我可以支持數百個連接。在收到消息時,我基本讀出ChannelID,然後查看信道期望的數據類型,然後將有效載荷讀入預期返回類型的新實例。 – 2012-07-10 04:52:26

+0

轉向此方法需要相當多的重構/重寫你的網絡代碼。但是,我可以說,改變我的代碼時獲得的價值非常巨大。現在添加新的動作/類型/事件非常容易,整個網絡代碼已經被減少了一半,並且簡單性使其更容易調試和管理 – 2012-07-10 04:56:00

2

所以:你基本上正在努力做到這一點,所以將數字代碼轉換爲方法的調用。

有些東西你不能得到,比如自動爲你完成這個轉換。如果您傳送方法的名稱,則可以使用反射來查找方法,然後調用它。因此,您必須執行一些手動工作來建立映射。

您必須決定的是將數字映射到方法的最佳方式。

一種方法就是您現在使用的方法。這裏的映射發生在調度週期內(取數,翻譯,調用)。問題是映射代碼掩蓋了調度代碼。還涉及相當數量的樣板代碼。

你可以使用類似這樣的命令模式的組合和散列映射:

在安裝過程中:

  1. 創建你的命令的通用接口(或使用閉包,因爲 您使用C#)
  2. 創建實現接口pr的對象實例。你想要映射的方法
  3. 將它添加到散列表。

在調度循環:

  1. 取數
  2. 查找號碼在哈希表
  3. 如果找到,調用對應的對象,否則失敗

對於更靈活的方法,將該數字視爲必須處理的消息,並使用模式責任鏈。

Command模式http://en.wikipedia.org/wiki/Command_pattern

責任http://en.wikipedia.org/wiki/Chain-of-responsibility_pattern

+0

這就是我所要做的。有一張映射將枚舉值映射到方法並查找並調用它們。 – 2012-07-11 07:50:37

+0

這也是我對這種情況的解決方案。它很好地分離了這些問題,並促進了Command模式的使用。 – 2012-07-11 08:45:26

相關問題