Архитектура лобби покера - PullRequest
4 голосов
/ 10 января 2012

Я создал систему онлайн-покера, используя WCF net.tcp и WPF для внешнего интерфейса. Это прекрасно работает, но я чувствую, что есть некоторые вещи, которые можно улучшить, когда я преобразую интерфейс в Silverlight.

Один из вопросов, которые у меня возникают к коллегам-архитекторам, заключается в том, как обновить игровое лобби? В лобби покерных игр постоянно обновляется статистика: количество игроков, количество раздач в час и процент флопа.

Поскольку в любой момент времени могут быть запущены сотни игр, я не уверен, что возвращение всего списка игр каждые 5 секунд (опрос) является оптимальным. Я думал об использовании дельта-запроса, поскольку во многих играх не будет обновлений статуса (например, нет игроков за столом).

Я думал об использовании времени обновления, чтобы каждый раз, когда клиент (который может быть сотнями или даже тысячами!) Опрашивал, возвращались только записи, обновленные в течение, скажем, 5, 10 или более секунд.

Клиент игрового лобби, конечно, будет отвечать за согласование новых данных, но я думаю, что это могло бы помочь снять часть нагрузки с игровых серверов.

Есть идеи?

Ответы [ 2 ]

2 голосов
/ 10 января 2012

Вы можете выбрать подход, при котором клиенты регистрируются на сервере для циклического обновления.Следовательно, сервер будет предоставлять сервисный контракт с контрактом обратного вызова (дуплексный контракт), который клиент должен будет выполнить.Подробности см. здесь .

С другой стороны, может быть сложно использовать дуплексный контракт от клиента Silverlight (я не уверен, если это вообще возможно), так что опросс интервалом обновления является легальным подходом.Сервер должен отправить текущую временную метку вместе с данными ответа цикла опроса, которые клиент отправит обратно со своим следующим запросом, чтобы указать, с какого момента запрашиваются обновленные данные.Избегайте сравнения времени клиента и сервера.

0 голосов
/ 27 апреля 2012
<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; }
    }
}
...