我有一个关于如何使用 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/