Wpf 扑克大厅建筑
我已经创建了一个在线扑克系统,前端使用WCF net.tcp和WPF。它工作得很好,但我觉得当我将前端转换为Silverlight时,有一些地方可以改进 我要问的一个问题是,游戏大厅应该如何更新?扑克游戏大厅不断更新玩家数量、每小时手数和翻牌百分比等统计数据 由于在任何给定的时间都可能有数百个游戏正在进行中,我不太确定每5秒返回一次完整的游戏列表(轮询)是否最佳。我考虑使用delta查询,因为很多游戏都不会有状态更新(例如:桌上没有玩家) 我考虑使用一个更新时间,这样每次客户机(可能是数百甚至数千!)轮询时,只返回在5、10秒或更长时间内更新的记录 游戏大厅客户端当然将负责协调新数据,但我认为这有助于减轻游戏服务器的一些负担Wpf 扑克大厅建筑,wpf,silverlight,wcf,architecture,poker,Wpf,Silverlight,Wcf,Architecture,Poker,我已经创建了一个在线扑克系统,前端使用WCF net.tcp和WPF。它工作得很好,但我觉得当我将前端转换为Silverlight时,有一些地方可以改进 我要问的一个问题是,游戏大厅应该如何更新?扑克游戏大厅不断更新玩家数量、每小时手数和翻牌百分比等统计数据 由于在任何给定的时间都可能有数百个游戏正在进行中,我不太确定每5秒返回一次完整的游戏列表(轮询)是否最佳。我考虑使用delta查询,因为很多游戏都不会有状态更新(例如:桌上没有玩家) 我考虑使用一个更新时间,这样每次客户机(可能是数百甚至数
有什么想法吗?您可以选择一种方法,让客户端在服务器上注册以进行周期性更新。因此,服务器将提供一个带有回调契约(双工契约)的服务契约,客户机必须实现回调契约。有关详细信息,请参阅 另一方面,从Silverlight客户机使用双工契约可能很困难(我不确定是否可能),因此使用更新时间间隔进行轮询是一种合法的方法。服务器应发送一个当前时间戳和轮询周期的响应数据,客户机将在下一个请求中发回该数据,以指示何时请求更新的数据。避免比较客户端和服务器时间。
<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; }
}
}
命名空间TestListUpdate
{
///
///Window1.xaml的交互逻辑
///
公共部分类Window1:Window
{
字典_gameData=null;
//这是一个测试,真实数据将通过web服务检索
列表_updates=null;
公共窗口1()
{
初始化组件();
//这是绑定到ListView控件的原始数据
这是。_gameData=new Dictionary();
这个._gameData.Add(1,新的gameData{Id=1,Creator=“ABC”,Name=“One”,Publisher=“123”});
这个.u gameData.Add(2,新的gameData{Id=2,Creator=“DEF”,Name=“Two”,Publisher=“456”});
这个._gameData.Add(3,新的gameData{Id=3,Creator=“GHI”,Name=“Three”,Publisher=“789”});
这个._gameData.Add(4,新的gameData{Id=4,Creator=“JKL”,Name=“Four”,Publisher=“abc”});
这个.u gameData.Add(5,新的gameData{Id=5,Creator=“MNO”,Name=“Five”,Publisher=“def”});
//这是测试数据,有些ID是上面原始数据的副本
//其他项目代表新项目
此。_updates=新列表();
这个._updates.Add(新游戏数据{Id=2,Creator=“DDD”,Name=“Two”,Publisher=“123”});
这个._updates.Add(新游戏数据{Id=3,Creator=“TTT”,Name=“Three”,Publisher=“456”});
这个._updates.Add(新游戏数据{Id=5,Creator=“FFF”,Name=“Five”,Publisher=“789”});
这个._updates.Add(新游戏数据{Id=6,Creator=“XXX”,Name=“Six”,Publisher=“abc”});
这个._updates.Add(新游戏数据{Id=7,Creator=“VVV”,Name=“Seven”,Publisher=“def”});
System.Windows.Threading.dispatchermer timer=新的System.Windows.Threading.dispatchermer();
timer.Interval=新的时间跨度(0,0,5);
timer.Tick+=新事件处理程序(timer\u Tick);
timer.Start();
}
无效计时器勾号(对象发送方,事件参数e)
{
//从新数据中获取ID列表
变量ID=(从本文件中的l开始。\u更新
选择l.Id);
//获取具有匹配ID的项目列表,
//这些数据将被更新
var updates=(从本节中的g开始).\u gameData
其中ids.Contains(g.Value.Id)
选择g);
//更新当前项目
对于(int i=0;ia.Id,a=>a)
).ToDictionary(q=>q.Key,q=>q.Value);
//这是重新绑定ListView控件的一个简单技巧
this.listView1.ItemsSource=null;
this.listView1.ItemsSource=游戏列表;
}
//数据绑定属性
公共词典游戏列表
{
获取{返回此。_gameData;}
}
}
//数据类
公共类游戏数据
{
公共int Id{get;set;}
公共字符串名称{get;set;}
公共字符串创建者{get;set;}
公共字符串发布程序{get;set;}
}
}
有趣的是,你应该提到双面打印。我通过IIS7和net.tcp在实际游戏中使用WCF双工操作。我不确定发布和订阅是否是大厅部分的最佳架构,因为在双工操作中,您需要做很多事情来处理负载平衡、故障切换等。此外,大厅在显示信息时会不断请求信息。当大厅窗口最小化时,我关闭了轮询间隔。你是对的,Pub/Sub的开销很大。事实上,在一个WCF