2011-12-04 39 views
3

我需要通過網絡(多人遊戲)傳輸.NET對象(具有層次結構)。爲了節省帶寬,我只想傳輸更改的字段(和/或屬性),所以不會更改的字段不會傳輸。通過網絡在每個字段上傳輸對象

我還需要一些機制來匹配其他客戶端合適的對象(全局對象標識符...類似對象ID?)

我需要一些建議,如何做到這一點。
你會使用反射嗎? (性能至關重要)
我還需要傳送IList delta(添加的對象,刪除的對象)的機制。

MMO網絡是如何完成的,它們是否傳輸整個對象?
(也許我的每場傳遞的想法是愚蠢的)

編輯:
要清楚:我已經有機制來追蹤變化(可以說每一個領域都有財產,二傳手增加場某種列表或字典,其中包含更改 - 結構不是最終的)。

我不知道如何序列化這個列表,然後在其他客戶端反序列化它。主要是如何有效地做到這一點,以及如何更新適當的對象。

這裏有大約一百個對象,所以我想避免當我爲每個對象編寫特殊函數的情況。使用屬性裝飾字段或屬性是可以的(例如指定序列化器,字段ID或類似的東西)。

關於對象的更多信息:每個對象平均有5個字段。一些對象從其他繼承。

謝謝你所有的答覆。

回答

2

另一種方法;不要嘗試序列複雜數據的變化:相反,只發送了實際命令申請(以簡潔形式),例如:

move 12432 134, 146 
remove 25727 

(這將移動1個對象和刪除其他)。

然後,您可以在接收器上應用這些命令,如果它們不同步,則允許完全重新同步。

我不建議你實際上使用文本 - 這只是爲了讓這個例子更清晰。

這是一件好事:它還提供免費的「重放」功能。

+0

感謝您的回答,我沒有考慮到這一點 –

1

這是不符合邏輯的轉移不僅改變字段,因爲你會浪費你的時間檢測哪些字段改變,哪些沒有,以及如何在接收方一端重建將大量的等待時間添加到您的遊戲,使它在網上無法播放。

我提出的解決方案是爲你分解你的對象是最小和發送這些小物件是快。另外,您可以使用壓縮來減少帶寬使用量。

爲對象ID,你可以用,當你建立一個新的對象,它增加了一個靜態的ID。

希望此回答有幫助。

+0

跟蹤髒字段可能相當便宜,具體取決於您是否樂意讓它「侵入」對象模型,並且可以實現顯着的序列化節省。 –

+0

但是,接收者怎麼知道它接收的是什麼字段,除非他做了一些額外的工作來識別髒。這是我的觀點,發送方有一個「小」的額外工作,接收方有一個「小」的額外工作。把它們結合起來,最後真的節省了多少? –

+0

接收者知道已經存在的字段標識(例如我給出的,以這種方式合併從協議基本上得到了支持,但是作爲類比:在XML中它將是「元素名稱」)。鑑於接收器*已經*必須這樣做,接收器處的成本恰好爲零。在發件人處,檢查一個bool比實際序列化任何東西便宜得多 - 因此在大多數情況下發件人會更便宜**,而在web everythig髒的情況下會非常輕微地增加(幾乎不可測量)。 –

2

跟蹤髒領域最便宜的方式是把它作爲你的對象模型,即的一個主要特點每個數據字段「foo」都有一個「fooDirty」字段,您在「set」中設置爲true(如果值不同)。這也可以與條件序列化結合起來,也許是少數序列化器觀察到的「ShouldSerializeFoo()」模式。我不知道任何與正好匹配的庫(除非我們包含DataTable,但是......想到小貓!)

也許另一個問題是需要跟蹤所有對象進行合併反序列化;這本身並不是免費的。因爲(重要的)支持條件序列化和合並,所以我認爲你可以在上面的行(fooDirty/ShouldSerializeFoo)中使用protobuf-net作爲序列化程序。我也建議等的接口:

ISomeName { 
    int Key {get;} 
    bool IsDirty {get;} 
} 

的IsDrty將允許您快速檢查所有的對象爲那些有改動,然後添加關鍵流,那麼(條件)序列化。調用者將讀取密鑰,獲取所需的對象(或使用該密鑰分配一個新對象),然後使用啓用合併的反序列化(傳入現有/新對象)。

不是一個完整的步驟,但是如果它是我,那是我將要看的方法。注意:子集中對象的添加/刪除/排序是一個棘手的方面,可能需要考慮。

1

您需要手動完成此操作。與手動製作的任何東西相比,自動跟蹤對象層次結構中的屬性和實例更改速度將非常緩慢。

如果您決定嘗試它,我會嘗試將您的對象映射到DataSet並使用其內置的修改跟蹤機制。不過,我仍然認爲你應該手工做這件事。

2

我只是說,馬克格雷維爾的建議是真正的方法。他掩蓋了一些細節,比如衝突解決(你可能想要讀一下Leslie Lamport的工作,他基本上花了他的整個職業生涯描述處理分佈式系統中衝突解決方法的不同方法),但這個想法是合理的。

如果您確實想傳輸狀態快照,而不是狀態更改的過程描述,那麼我建議您查看構建快照差異作爲前綴樹。基本思想是你構造了一個對象和字段的層次結構。當您更改一組字段時,它們的任何常用前綴都只包含一次。這可能看起來像:

world -> player 1 -> lives: 1 
...    -> points: 1337 
...    -> location -> X: 100 
...       -> Y: 32 
... -> player 2 -> lives: 3 

(在「...」中的所有內容只傳輸一次)。