【问题标题】:How do I specify a timeout in milliseconds for connection and send for multiple TCP connections?如何指定连接超时(以毫秒为单位)并发送多个 TCP 连接?
【发布时间】:2013-06-11 15:16:52
【问题描述】:

我有多个阻塞的 TCP 客户端试图连接服务器并将数据发送到服务器。然而,每个操作不应超过 500 毫秒,因为数据是时间相关的。超时时,它应该重试。我见过alarm() 方法,但它只接受秒。有什么好的方法吗?

【问题讨论】:

  • 使用 UDP 而不是 TCP。
  • 我不拥有这些服务器。 UDP不是一个选择:(
  • 您是使用每个客户端的线程/进程,还是使用select
  • alarm 不适用于线程。请参阅我的扩展答案。

标签: perl sockets timeout


【解决方案1】:

Time::HiRes 模块为您提供了一个具有微秒粒度的函数ualarm

【讨论】:

  • 所以我将使用local $SIG{ALRM} = sub { die 'Timed Out'; }; alarm 1; 而不是local $SIG{ALRM} = sub { die 'Timed Out'; }; ualarm 500; ???
  • 差不多。由于 ualarm 使用微秒,您将使用 500*1000
【解决方案2】:

如果每个连接都有一个子进程,则可以使用Time::HiResualarm。否则,我不明白你为什么会想使用alarm。它甚至对线程没有帮助(因为信号被发送到进程)。

更好的方法是记录连接的建立时间,如果您在随后的 0.5 秒后收到来自客户端的数据,则断开连接。 Time::HiRes 提供了一个返回小数秒的time 版本。

无论您如何提供并行性(线程、子进程、select、非阻塞操作),这种方法都有效。它适用于 TCP 和 UDP。它甚至是便携的。

如果一切都在同一个线程和进程中,您可以通过在从任何连接获取数据时扫描所有连接以查找超时来更快地丢弃死连接。


alarm 不会帮助你处理线程。

  1. 如果在启动线程之前设置处理程序,线程中的调用不会中断。

    use strict;
    use warnings;
    use threads;
    
    use Time::HiRes qw( time ualarm );
    
    local $SIG{ALRM} = sub { };
    
    {
       ualarm(2 * 1_000_000);
       my $s = time;
       sleep(5);
       my $e = time;
       print "Slept for ".($e-$s)." seconds\n";
    }
    
    for my $thread_idx (0..1) {
       async {
          ualarm(2 * 1_000_000) if $thread_idx == 0;
          my $s = time;
          sleep(5);
          my $e = time;
          print "Thread $thread_idx slept for ".($e-$s)." seconds\n";
       };
    }
    
    $_->join for threads->list;
    

    输出

    Slept for 2.00284504890442 seconds
    Thread 0 slept for 5.00048089027405 seconds
    Thread 1 slept for 5.00327205657959 seconds
    
  2. 在线程中设置处理程序完全没有影响。

    use strict;
    use warnings;
    use threads;
    
    use Time::HiRes qw( time ualarm );
    
    for my $thread_idx (0..1) {
       async {
          local $SIG{ALRM} = sub { };
          ualarm(2 * 1_000_000) if $thread_idx == 0;
          my $s = time;
          sleep(5);
          my $e = time;
          print "Thread $thread_idx slept for ".($e-$s)." seconds\n";
       };
    }
    
    $_->join for threads->list;
    

    输出

    Alarm clock
    

【讨论】:

  • 首先感谢您的详细解释。在 Windows 上,我在函数之外创建了固定数量的阻塞套接字,并且创建了相同数量的线程,计数变量每毫秒增加 1,当然还有更多线程用于处理每个套接字。当计数器达到 500 时,我正在关闭相关的套接字,以便释放该块。如果它没有超时,我会将计数器重置为 0。然而,我在 Linux 中完全对 perl 感到困惑......
猜你喜欢
  • 2019-12-26
  • 1970-01-01
  • 2012-08-17
  • 1970-01-01
  • 2020-10-25
  • 1970-01-01
  • 2022-01-20
  • 2016-02-17
  • 2017-07-27
相关资源
最近更新 更多