perl - 在 Perl 中正确使用 IO::Socket::INET 作为 TCP 客户端

标签 perl sockets tcp

我有一个关于如何使用 IO::Socket 的问题;我有一个应该不断运行的脚本,监视 Asterisk 服务器的某些事件。当这些事件发生时,脚本通过 TCP 套接字将事件数据发送到另一台服务器。我发现套接字有时会关闭。我的问题是我是否应该使用单个套接字,并使其永远保持打开状态(并找出原因+阻止它关闭),或者我应该为发送的每一位数据打开和关闭一个新套接字?
我对这类事情的经验非常少,我已经阅读了所有文档,但没有找到我正在寻找的答案。以下是我到目前为止所得到的示例:

#!/usr/bin/perl
use Asterisk::AMI;
use IO::Socket;
use strict;
use warnings;

my $sock = new IO::Socket::INET (
  PeerAddr => '127.0.0.1',
  PeerPort => '1234',
  Proto => 'tcp',
);

sub newchannel {
  my ($ami, $event) = @_;

  if ($event->{'Context'} eq "from-trunk") {

    my $unique_id = $event->{'Uniqueid'};
    my $this_call = $call{$unique_id};

    $this_call->{caller_name} = $event->{'CallerIDName'};
    $this_call->{caller_number} = $event->{'CallerIDNum'};
    $this_call->{dnis} = $event->{'Exten'};

    $call{$unique_id} = $this_call;
  };

}

sub ringcheck {
  my ($ami, $event) = @_;

  if ($event->{SubEvent} eq 'Begin') {
    my $unique_id = $event->{UniqueID};
    if (exists $call{$unique_id}) {

      my $this_call = $call{$unique_id};

      $this_call->{system_extension} = $event->{Dialstring};
      $this_call->{dest_uniqueid}  = $event->{DestUniqueID};


      printf $sock "R|%s|%s|%s||%s\n",
        $this_call->{caller_name},
        $this_call->{caller_number},
        $this_call->{system_extension},
        $this_call->{dnis};

      $this_call->{status}  = "ringing";
  }
}

还有更多的内容,但这显示了我觉得我应该在哪里启动/停止一个新的套接字(在ringcheck sub内)。

如果您需要我澄清或添加任何内容,请告诉我。

谢谢!

最佳答案

为每条消息建立新连接还是保持连接打开更好取决于几个因素:

  • 与建立连接相关的开销是否很大?这取决于需要发送消息的频率以及网络连接的质量等因素。

    如果远程端是“localhost”(如上面的示例脚本所示),那么这不太可能成为问题,事实上在这种情况下,我无论如何都会建议使用 Unix 域套接字。

  • 远端是否发回任何内容?如果任何一方都可能有异步消息要发送,那么管理零星连接就会变得更加困难。但听起来您的情况并非如此。

  • 保持连接打开是否会占用任何重要资源?

请注意,我不认为随机连接丢失是争论每次建立新连接的充分理由。如果可能的话,无论如何最好诊断该问题。否则,无论采取什么方法,您都可能获得不可靠的性能。

根据我的经验,长期保持 TCP 连接中看似随机丢失的一个非常常见的原因是中间跟踪防火墙。如果此类防火墙在一段时间内没有看到任何事件,就会断开连接,以节省自己的资源。解决这个问题的一种方法是在套接字上设置套接字选项 SO_KEEPALIVE,如下所示:

use Socket;
...
setsockopt($sock, SOL_SOCKET, SO_KEEPALIVE, 1);

这有几个好处 - 它会导致内核定期在您的连接上发送保活消息,即使一切都很安静,这本身就足以让一些防火墙满意。另外,如果您的连接确实断开,您的程序可以立即发现,而不是下次您想要写入时(尽管您可能不会注意到它,除非您定期检查套接字上的错误)。

也许你最好的方法可能是设置 SO_KEEPALIVE,并保持套接字打开,但每当你尝试写入时也要检查错误,如果有错误,请关闭并重新打开连接。

This question可能对您也有用。

关于perl - 在 Perl 中正确使用 IO::Socket::INET 作为 TCP 客户端,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24948154/

相关文章:

windows - mongodb : listen() attempts to access socket in a forbidden way

c++ - 客户端-服务器回显程序陷入UDP死锁

perl - Perl 如何在内存中存储整数?

perl - 在 Windows 上构建 TAP::Formatter::HTML 时遇到问题

perl - 在 msysgit 中为 git-remote-mediawiki 使用完整的 perl 库

c - AF_UNIX 套接字中缓冲区的最大长度

java - 需要阻塞直到接收到特定字符序列的 TCPIP 客户端

go - 在 golang 中通过 TCP 套接字发送数百万条短消息

java - 负载均衡器、套接字和 Java

perl - Moose:构建器需要一个有时未设置的值(非确定性)