我试图创建一个保持计时器。这意味着客户端将每1分钟向服务器发送一个问候消息。如果服务器在保持定时器内没有从客户端获取hello数据包,则客户端将被删除。 我可以和一个客户做得很好...... 但对于多个我无法弄明白。 我正在考虑创建一个线程foreach连接到服务器的新客户端。然后在该线程内部启动一个保持计时器..但我如何区分客户端与线程,以及如何重置保持计时器如果从客户端收到一个hello数据包。
我想为每个hello数据包创建一个新线程并停止旧数据包。 但我不知道这将是如何cpu密集
如果你不理解我的问题,请说出来,并试着解释你不理解的任何事情。
哪种解决方案更好? 解决方案A) 每当hello数据包到达时,启动一个新线程并停止旧线程? (每40秒) - 来自100个客户
解决方案B) 在这里插入更好的可扩展解决方案。
解决方案C) 我可以在动态创建的线程中访问计时器吗? - 我在所有动态创建的线程上都有唯一的线程名称。
public void _clientholdtimer()
{
holdtimer = new Timer();
holdtimer.Interval = SECtoMS(Settings.Default.Hold);
holdtimer.Elapsed += holdtimer_Elapsed;
}
当我从客户端收到一个与线程同名的hello数据包时重置它?
解决方案D) 将计时器存储在字典中 public Dictionary timersDict = new Dictionary(); 并且循环在dict中找到关于hello数据包接收重置该定时器的引用。?
foreach(var item in timersDict)
{
if(item.Key == stripip(client.RemoteEndPoint.ToString()))
TimerReset(item.Value);
}
解
设置远程主机应用程序,每隔3秒向服务器发送一条“hello”消息。 在服务器上创建一个计时器,每1秒发生一次经过的事件。 设置一个静态值来保存一个int,它决定了,在我认为远程机器死了多久之前,我选择了9秒。
当服务器收到hello消息时,它会将时间戳存储在列表中,并显示客户端的IP地址。
在timer_elapsed事件
上void holdtimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
try
{
if (server.Clients.GetAllItems().Count != 0)
{
foreach (IScsServerClient _client in server.Clients.GetAllItems())
{
string ipaddr = stripip(_client.RemoteEndPoint.ToString());
bool containsentry = _clientlist.Any(item => item.ipadress == ipaddr);
if (containsentry)
{
foreach (Scsserverclient entry in _clientlist.Where(entry => entry.ipadress == ipaddr))
{
if ((DateTime.Now - TimeSpan.FromSeconds(Settings.Default.Hold)) > entry.lasthello &&
entry.isConnect != "Disconnected")
{
entry.client.Disconnect();
}
}
}
}
}
}
catch (Exception ex)
{
}
}
基本上我会查看连接的客户端列表,如果上次收到的hello消息超过9秒,我认为客户端已断开连接。
答案 0 :(得分:7)
这是Reactive Extensions的完美应用程序。这是一个快速的应用程序示例,您可以尝试(添加Nuget包Rx-Main)。它通过要求您为其ID输入整数来模拟客户端。在看到特定ID后经过timeToHold后,将运行Subscribe中的操作。
使用Synchronize很重要 - 从RX版本2开始,没有同步调用,Subject OnNext不是线程安全的。
多亏了RX,这个解决方案在使用定时器和线程方面非常有效。
注意:我在我的博客上添加了更详细的解释:http://www.zerobugbuild.com/?p=230
public void Main()
{
var clientHeartbeats = new Subject<int>();
var timeToHold = TimeSpan.FromSeconds(5);
var expiredClients = clientHeartbeats
.Synchronize()
.GroupBy(key => key)
.SelectMany(grp => grp.Throttle(timeToHold));
var subscription = expiredClients.Subscribe(
// in here put your disconnect action
i => Console.WriteLine("Disconnect Client: " + i));
while(true)
{
var num = Console.ReadLine();
if (num == "q")
{
break;
}
// call OnNext with the client id each time they send hello
clientHeartbeats.OnNext(int.Parse(num));
}
// if you need to tear down you can do this
subscription.Dispose();
}
附录:哦,如果您的服务器负责启动客户端,您可能希望在启动客户端时从服务器发送OnNext,以防客户端从不发送心跳。
答案 1 :(得分:2)
如果我理解你的问题,我会做什么:
您可以使用ConcurrentDictionary
进行集合,以轻松编写线程安全的代码。