2011-06-30 20 views
5

注意聯網應用程序的設計幫助?

這是一個相當大的問題,所以請原諒我提前道歉,如果這還不清楚。爲了使這個問題易於管理,並儘量減少混淆,我省略了複製粘貼類的一些屬性。

背景

我正在寫一個網絡應用 - 一個「遠程桌面」類型的應用程序,使平均技術人員書呆子可以幫助他的朋友或鄰居計算機的問題。我意識到像TeamViewer這樣的免費和更先進的軟件存在,但這個問題沒有討論創建這個軟件的實用性。

常用術語

客戶是技術人員的書呆子,助手 - 在控制器服務器是'受害者',一個遇險者。 客戶端通常是向服務器發起命令的客戶端。

信息

這個軟件是不是一個實時顯示/控制應用程序更多。我想額外模塊,如文件資源管理器模塊聊天模塊這樣他們就可以既無需使用額外的即時通訊軟件通信)。

最初,我通過UDP發送和接收消息的方法是手動和低效的。 (我使用Lidgren庫UDP網絡所以這就是爲什麼我的包沒有顯示出低水平字節像的頭信息的大小。

Original Packet Structure: 

Byte Index Type  Purpose/Description 
------------------------------------------------------ 
0    byte  The intended destination module (e.g. 1 -> Chat module) 
1    byte  The command for this module to perform (e.g. 0 -> NewChatMessage) 
2    byte  Encryption/compression flag 
3    byte  Packet priority flag (e.g. Cancel packets should be processed first) 
4-X   ?  Command-specific arguments of variable type (e.g. For this example, the argument would be the actual chat message text) 

這種方法變得困難,一旦我頭100來包裝我的頭+消息。來源變得神祕,修改是一件苦差事。即使將「目標模塊」和「命令」編碼爲枚舉(仍然是間接編號),開發應用程序仍然很困難。當接收到這些數據包時,解析特定於命令的參數會變成一個可笑的長切換梯形圖,嵌套在一個可觀的長if-else梯形圖中。

我後來決定爲我的數據包結構使用序列化。我現在可以將每個命令設計爲一個類,然後將其序列化爲一個緊湊的字節數組(或字符串),然後將其反序列化回原始類並將參數作爲類屬性讀取。這似乎更容易,我願意爲更大的序列化數據結構支付帶寬成本。

Revised Packet Structure: 

Byte Index Type  Purpose/Description 
------------------------------------------------------ 
0-X   String Serialized class 

的問題

但這個問題是設計中的一個。序列化和反序列化我的類沒有問題。問題在於我如何設計我的命令/包類。我發現自己在做着this。我的課的設計是下面:

包基類

/// <summary> 
/// The fundamental unit of network communication which can be transmitted and received from client to server. Contains the destination module and module-specific command. 
/// </summary> 
public class Packet 
{ 
    /// <summary> 
    /// Specifies the module this packet is forwarded to. 
    /// </summary> 
    public Module DestinationModule { get; set; } 

    /// <summary> 
    /// Specifies whether this packet is encrypted or compressed. 
    /// </summary> 
    public EncryptionCompressionFlag EncryptedOrCompressed { get; set; } 

    /// <summary> 
    /// Specifies the packet's priority. 
    /// </summary> 
    public PacketPriority Priority { get; set; } 
} 

歡迎模塊包基(更多相關信息如下)

/// <summary> 
/// Base packet structure for packets specific to this module. Adds a ModuleCommand property from the base Packet class. 
/// </summary> 
public class WelcomeModulePacket : Packet 
{ 
    /// <summary> 
    /// Specifies the command number this particular packet is instructing the module to execute. 
    /// </summary> 
    public ModuleCommand Command { get; set; } 
} 

/// <summary> 
/// Specifies the commands for this module. 
/// </summary> 
public enum ModuleCommand : byte 
{ 
    /// <summary> 
    /// The user has just clicked the Connect button (on form's GUI) and is sending this connect packet. 
    /// </summary> 
    ClientRequestingConnectionPacket = 0, 

} 

解釋爲 'WelcomeModulePacket'類:

因此,因爲我有兩個以上的模塊,有單個枚舉'CommandModule'枚舉命令所有模塊,將是一個非常長的枚舉和相當混亂。這就是爲什麼我有一個不同「ModuleCommand」爲每個模塊枚舉。

連接包

/// <summary> 
/// The user has just clicked "Connect" on the Welcome form of the client. The client is now requesting a connection to the server. 
/// </summary> 
public class ClientRequestingConnectionPacket : WelcomeModulePacket 
{ 
    public string Username { get; set; } 
    public string Password { get; set; } 
} 

所以,你可以看到我的課不僅有繼承的兩層,但。

ClientRequestingConnectionPacket : WelcomeModulePacket : Packet 

這種設計的問題是顯而易見的,當我喜歡'ClientRequestingConnectionPacket者的特定數據包存儲到較不具體的數據結構。例如,將「ClientRequestingConnectionPacket」排入通用的PriorityQueue(對於優先級排序,請記住'Packet'類如何具有'PacketPriority'屬性)。當我出列,這個數據包,它是出隊爲,不是ClientRequestingConnectionPacket。在這種情況下,因爲在那裏孤單隻有一個包,我明明知道數據包的原始類型是ClientRequestingConnectionPacket,但是當我存儲數百包在排隊,我沒有任何辦法知道原來的具體鍵入將其恢復。

所以我做了奇怪的補充,如添加該屬性:

Type UltimateType { get; set; } 

的「包」基類。但我的意思是,這個「解決方案」似乎非常強制和原始,我不相信它是一個真正的解決方案。

因此,基於該鏈接的上述其他StackOverflow的問題上,我是不是犯那個錯誤?我如何解決它?這叫做什麼?我應該如何設計我的應用程序?

經修訂的課題:什麼是對包類相應的設計模式?

+0

這聽起來像測試類型[工廠模式](http://en.wikipedia.org/wiki/Abstract_factory_pattern)工廠模式將允許您在運行時指定對象的類型。 –

+0

也許考慮組合(並將組合類型暴露)在繼承之上。 – 2011-06-30 03:46:24

+0

考慮編輯你的問題。它過長,而且大部分無關信息。標籤「網絡編程」似乎與您的問題毫無關係。 –

回答

1

您可以使用GetType爲FishBasketGordo建議,或者您也可以使用is

if (packet is ClientRequestingConnectionPacket) 
{ /* do something */ } 
else if (packet is SomeOtherPacket) 
.... 
1

當您反序列化您的對象時,當您撥打GetType時會返回什麼內容?如果我沒有弄錯,它將是實際的,具體的類型,而不是一般的基本類型。這樣你需要添加一個額外的屬性來知道實際的類型。