2012-01-10 6 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

웃기는 당신은 양면을 언급해야합니다. IIS7과 net.tcp를 통해 WCF 이중 작업을 사용하여 실제 게임을합니다. 게시 및 구독은로드 균형 조정, 장애 조치 (failover) 등을 처리하기 위해해야 ​​할 일이 많기 때문에 로비 부분에 가장 적합한 아키텍처가 될 것입니다. 양방향 작동. 또한 로비는 로비를 통해 정보를 요청합니다. 로비 창이 최소화되면 폴링 간격을 차단합니다. – NickV

+0

맞습니다. Pub/Sub는 많은 오버 헤드입니다. 사실, WCF 기반 프로젝트 중 하나에서 저는 현재 주기적으로 폴링에 찬성하여 agaist로 결정했습니다 :-) – Clemens