【问题标题】:Hold timer type thread保持定时器型螺纹
【发布时间】:2013-05-16 11:16:53
【问题描述】:

我很难自己解决这个问题,因此在这里问。 我有一个在远程机器上安装客户端的应用程序 客户端通过套接字返回报告。

我正在尝试创建一个保持计时器。这意味着客户端将每 1 分钟向服务器发送一个 hello 消息。如果服务器在保持计时器内没有收到来自客户端的 hello 数据包,则客户端被删除。 我可以和一个客户一起做... 但对于多个我无法弄清楚。 我正在考虑为连接到服务器的每个新客户端创建一个线程。然后在该线程内启动一个保持计时器。但是我如何通过线程将客户端与另一个客户端区分开来,以及如果从客户端收到一个 hello 数据包,我如何重置保持计时器。

我想为每个 hello 数据包创建一个新线程并停止旧线程。 但我不知道这会占用多少 CPU 资源

如果你不明白我的问题,请说出来,我会尽力解释你不明白的。

哪种解决方案更好? 解决方案 A) 每次问候数据包到达时启动一个新线程并停止旧线程? (每 40 秒)- 来自 100 个客户

解决方案 B) 在此处插入更好、更具可扩展性的解决方案。

解决方案 C) 我可以访问我动态创建的线程内的计时器吗? - 我在所有动态创建的线程上都有唯一的线程名。

public void _clientholdtimer()
    {          
    holdtimer = new Timer();
    holdtimer.Interval = SECtoMS(Settings.Default.Hold);
    holdtimer.Elapsed += holdtimer_Elapsed;          
    }

当我从客户端收到与线程同名的 hello 数据包时重置它?

解决方案 D) 将计时器存储在字典中 公共词典 timersDict = new Dictionary(); 并且循环在接收到的 hello 数据包的 dict 中找到引用重置该计时器。?

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 秒,我会考虑让客户端断开连接。

【问题讨论】:

  • 您可以发布您已有的代码吗?我找不到任何会阻止您设计解决方案的具体问题。也许更容易看到你做错了什么并指出来。
  • 嗯,就是这样,我无法解决这个问题。我没有无效的代码。我想不出这样做的最佳方法
  • 你能让服务器成为一个 ASP.NET 应用程序并让客户端通过 HTTP 调用服务器吗?这样一来,基础架构就可以管理连接,所有这些问题都消失了。
  • 我不能这样做。套接字按应有的方式工作并且客户端受到管理,保持计时器是服务器端而不是客户端 - 当我在服务器上收到一条消息时,客户端发送一个带有 client.ID 的字符串“hello#”,我将 case 切换为“hello#”

标签: c# multithreading timer system.reactive


【解决方案1】:

这是响应式扩展的完美应用。这是一个您可以尝试的快速控制台应用示例(添加 Nuget 包 Rx-Main)。它通过要求您为他们的 ID 输入一个整数来模拟客户。在看到特定 ID 后 timeToHold 已过,订阅中的操作将运行。

使用 Synchronize 很重要 - 从 RX 版本 2 开始,如果没有 Synchronize 调用,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,以防客户端发送心跳。 p>

【讨论】:

  • 更新了我的博客,提供了有关此技术的更多信息:zerobugbuild.com/?p=230
  • 我会将此标记为解决方案。我没有将它用于我的应用程序,但它似乎是解决我的问题的一个非常好的解决方案,而且我确实使用了这背后的一些逻辑。
【解决方案2】:

如果我理解了您的问题,我会怎么做:

  • 创建一个唯一的集合,存储客户端的标识符、关联的套接字对象(或断开连接所需的任何内容)以及最后收到“hello”的日期
  • 让单个线程(或计时器)每隔几百毫秒迭代一次集合,检查日期并删除过时的连接
  • 当客户端发送“hello”时,在集合中找到适当的条目,并更新关联的日期。

您可以使用ConcurrentDictionary 作为集合,轻松编写线程安全代码。

【讨论】:

  • “使用 ConcurrentDictionary ...轻松编写线程安全代码” - 显然你过着迷人的生活 :) 如果你见过我见过的恐怖......跨度>
  • @JamesWorld :D Lemme rephrase:为了轻松编写线程安全代码,假设您知道自己在做什么
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-28
  • 2011-04-01
  • 2011-05-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多