2012-01-10 71 views
4

我創建了一個使用WCF net.tcp和WPF作爲前端的在線撲克系統。它工作的很好,但是當我將前端轉換爲Silverlight時,我感覺有些事情可以改進。撲克大廳架構

我對其他建築師的問題之一是遊戲大廳應該如何更新?撲克遊戲大廳會不斷更新統計數據,如玩家人數,每小時手數和失敗百分比。

由於在任何特定時間可能會有數百個遊戲正在進行,因此我不太確定每5秒返回整個遊戲列表(輪詢)是否最佳。我正在考慮使用增量查詢,因爲許多遊戲不會有狀態更新(例如:桌上沒有玩家)。

我正在考慮使用更新時間,所以每次客戶端(可能是數百甚至數千!)輪詢時,只返回在5,10或更多秒內更新的記錄。

遊戲大廳客戶端當然會負責協調新的數據,但我認爲這可以幫助減輕遊戲服務器的一些負擔。

任何想法?

回答

0
<Window x:Class="TestListUpdate.Window1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="Window1" Height="300" Width="300"> 
    <Grid> 
     <ListView Name="listView1"> 
      <ListView.View> 
       <GridView> 
        <GridViewColumn Width="140" Header="Name" DisplayMemberBinding="{Binding Value.Name}" /> 
        <GridViewColumn Width="140" Header="Creator" DisplayMemberBinding="{Binding Value.Creator}" /> 
        <GridViewColumn Width="140" Header="Publisher" DisplayMemberBinding="{Binding Value.Publisher}" /> 
       </GridView> 
      </ListView.View> 
     </ListView> 
    </Grid> 
</Window> 


namespace TestListUpdate 
{ 
    /// <summary> 
    /// Interaction logic for Window1.xaml 
    /// </summary> 
    public partial class Window1 : Window 
    { 
     Dictionary<int, GameData> _gameData = null; 

     // This is a test, real data will be retrieved via a web service 
     List<GameData> _updates = null; 

     public Window1() 
     { 
      InitializeComponent(); 

      // This is the original data bound to the ListView control 
      this._gameData = new Dictionary<int, GameData>(); 
      this._gameData.Add(1, new GameData { Id = 1, Creator = "ABC", Name = "One", Publisher = "123" }); 
      this._gameData.Add(2, new GameData { Id = 2, Creator = "DEF", Name = "Two", Publisher = "456" }); 
      this._gameData.Add(3, new GameData { Id = 3, Creator = "GHI", Name = "Three", Publisher = "789" }); 
      this._gameData.Add(4, new GameData { Id = 4, Creator = "JKL", Name = "Four", Publisher = "abc" }); 
      this._gameData.Add(5, new GameData { Id = 5, Creator = "MNO", Name = "Five", Publisher = "def" }); 

      // This is test data, some Ids are duplicates of the original data above 
      // other items represent new items 
      this._updates = new List<GameData>(); 
      this._updates.Add(new GameData { Id = 2, Creator = "DDD", Name = "Two", Publisher = "123" }); 
      this._updates.Add(new GameData { Id = 3, Creator = "TTT", Name = "Three", Publisher = "456" }); 
      this._updates.Add(new GameData { Id = 5, Creator = "FFF", Name = "Five", Publisher = "789" }); 
      this._updates.Add(new GameData { Id = 6, Creator = "XXX", Name = "Six", Publisher = "abc" }); 
      this._updates.Add(new GameData { Id = 7, Creator = "VVV", Name = "Seven", Publisher = "def" }); 

      System.Windows.Threading.DispatcherTimer timer = new System.Windows.Threading.DispatcherTimer(); 
      timer.Interval = new TimeSpan(0, 0, 5); 
      timer.Tick += new EventHandler(timer_Tick); 
      timer.Start(); 
     } 

     void timer_Tick(object sender, EventArgs e) 
     { 
      // Get a list of Ids from the new data 
      var ids = (from l in this._updates 
         select l.Id); 

      // Get a list of items that have matching Ids, 
      // this data will be updated 
      var updates = (from g in this._gameData 
          where ids.Contains(g.Value.Id) 
          select g); 

      // Update the current items 
      for (int i = 0; i < updates.Count(); ++i) 
      { 
       KeyValuePair<int, GameData> kvp = updates.ElementAt(i); 
       kvp.Value.Publisher = DateTime.Now.ToLongTimeString(); 
      } 

      // This represents new items to add 
      this._gameData = this._gameData.Concat(
        (from n in this._updates 
        where !this._gameData.ContainsKey(n.Id) 
        select n).ToDictionary(a => a.Id, a => a) 
       ).ToDictionary(q => q.Key, q => q.Value); 

      // This is a simple trick to rebind the ListView control 
      this.listView1.ItemsSource = null; 
      this.listView1.ItemsSource = GameList; 
     } 

     // Databinding property 
     public Dictionary<int, GameData> GameList 
     { 
      get { return this._gameData; } 
     } 
    } 

    // Data class 
    public class GameData 
    { 
     public int Id { get; set; } 
     public string Name { get; set; } 
     public string Creator { get; set; } 
     public string Publisher { get; set; } 
    } 
} 
2

您可以選擇客戶端在服務器上註冊以進行循環更新的方法。因此,服務器將提供服務合同和客戶必須執行的回調合同(雙面合同)。詳情請參閱here

另一方面,從Silverlight客戶端使用雙工合同可能會很困難(我不確定是否有可能),所以使用更新時間間隔進行輪詢是一種合法的方法。服務器應該發送一個當前的時間戳和一個輪詢週期的響應數據,客戶端將在發送請求更新的數據時發送下一個請求以指示它。避免比較客戶端和服務器時間。

+0

有趣的,你應該提到雙面打印。我使用WCF雙工操作通過IIS7和net.tcp實際的遊戲。我不確定發佈和訂閱會是大廳部分的最佳體系結構,因爲您需要做很多事情來處理負載平衡,故障轉移等雙工操作。另外,大廳在顯示時請求信息。當大廳窗口最小化時,我關閉了輪詢間隔。 – NickV 2012-01-10 19:45:57

+0

你是對的,Pub/Sub是一個很大的開銷。事實上,在我目前正在開發的基於WCF的項目之一中,我剛剛決定採用循環輪詢方式:-) – Clemens 2012-01-10 19:52:13