Perl IO::Socket::INET+;IO::Async::Stream在断开连接时重新连接到TCP服务器

Perl IO::Socket::INET+;IO::Async::Stream在断开连接时重新连接到TCP服务器,perl,sockets,events,tcp,Perl,Sockets,Events,Tcp,就我的一生而言,我似乎不知道如何在断开连接后重新连接标准TCP套接字连接,特别是在IO::Async::Loop的上下文中 一些基本知识: #!/usr/bin/perl use strict; use warnings; use Socket; use IO::Async::Loop; use IO::Async::Stream; use IO::Socket; use Time::HiRes qw(usleep); # standard event loop my $loop = IO::

就我的一生而言,我似乎不知道如何在断开连接后重新连接标准TCP套接字连接,特别是在IO::Async::Loop的上下文中

一些基本知识:

#!/usr/bin/perl
use strict;
use warnings;
use Socket;
use IO::Async::Loop;
use IO::Async::Stream;
use IO::Socket;
use Time::HiRes qw(usleep);

# standard event loop
my $loop = IO::Async::Loop->new;

# notification service socket connection; we only write outgoing
my $NOTIFY = IO::Socket::INET->new(
    PeerHost => $a_local_network_host,
    PeerPort => $comm_port,
    Proto => 'tcp',
    Type => SOCK_STREAM,
    ReuseAddr => 1,
    Blocking => 0
) or warn("Can't connect to NOTIFY: $!\n");
setsockopt($NOTIFY, SOL_SOCKET, SO_KEEPALIVE, 1);

# main interface element via IO::Async
my $notifystream = IO::Async::Stream->new(
    handle => $NOTIFY,
    on_read => sub {
        my ( $self, $buffref, $eof ) = @_;
        # here's where we need to handle $eof if the remote goes away
        if($eof) {
            # i have tried several things here
            usleep(200000); # give the remote service some milliseconds to start back up
            # process fails if remote is not back up, so i know the timeout is 'good enough' for this test
            # attempt to reconnect.  have also tried recreating from scratch
            $NOTIFY->connect("$a_local_network_host:$comm_port");
            # this doesn't seem to have any effect
            $self->configure(handle=>$NOTIFY);
        }
    }
);
$loop->add( $notifystream );

# kickstart the event loop
$loop->run;

### -- Meanwhile, elsewhere in the code -- ###

$notifystream->write("data for notification service\n");
事实上,循环中还有很多事情在进行。我还有更复杂的方法来测试套接字是否关闭或断开,$notifystream上的更多错误处理程序,以及更好的超时/回退以重新连接到远程服务,不过这应该说明我正在做的主要工作

当远程服务器因任何原因离开时,我希望尝试重新连接到它,而不会中断系统的其余部分。在大多数情况下,远程设备干净地发送eof,因为它是有意重新启动的(不是我的选择,只是我必须处理的事情),但我也希望处理其他通信错误

在实践中,上述代码的作用就像它工作一样,但是远程服务不再接收对$notifystream的进一步写调用。不会生成错误,$notifystream愉快地进行进一步写入,但不会将它们传递到远程

我觉得我做错了。我不想重写应用程序事件循环的其余部分,因此请不要使用“just use AnyEvent”(仅使用AnyEvent)类型的响应——我真的希望更好地了解如何重新连接/重用/重新创建此处使用的变量(IO::Socket::INET和IO::Async::Stream),以便在远程服务器暂时不可用时进行补偿

欢迎对此目标提出任何建议或参考。谢谢

-=-=-=-=-

总结我收到(和未收到)的错误: 如果我没有留下usleep,由于远程服务不可用,基本套接字的重新连接(或重新连接)将失败。 如果我尝试从头开始重新创建套接字,然后“配置”流,我会得到“无法在未定义时调用方法sysread”,这让我相信套接字没有正确地重新创建。 流的内置“on_read_error”或“on_write_error”处理程序在任何时候都不会启动,不管我用当前代码向套接字写入了多少,尽管如果我完全销毁套接字,这些将生成错误。 在我知道套接字已关闭后,它似乎仍然处于活动状态,重新连接似乎不会改变任何事情。未生成错误,但未写入套接字


是否有不同的语法用于重新连接到IO::Socket::INET Socket?到目前为止,对->connect()的调用或从头开始重建似乎是关闭连接的唯一选项,两者似乎都不起作用。

您无法多次连接现有套接字。您只能关闭套接字并创建新的套接字。这与IO::Socket::INET、IO::Async::Stream甚至Perl无关,但Socket API就是这样工作的


详细说明:本地套接字实际上从未断开连接,即它仍然被配置为从特定的本地IP地址和端口发送数据,并发送到特定的地址和端口。只是,由于底层TCP连接断开或关闭(即FIN交换),发送将不再工作。由于没有API来解除绑定和断开套接字的连接,因此唯一的方法是关闭它并创建一个新的套接字,该套接字在调用connect之前是未绑定和未连接的。然后,这个新套接字可能会或可能不会获得与前一个相同的文件描述符。

我没有看到任何错误检查?你提到你有他们,他们怎么说?您当然需要“重新启用”重启功能,这些错误将有助于找出原因。IO::Async::Stream中有“on_read_error”、“on_write_error”和“on_writeable_stop”——它们都没有触发。完全我也试过了——问题是什么都不会出错。它就是不起作用。您是否尝试在
$NOTIFY
上重新连接?这个问题不清楚。您可能需要也可能不需要再次将
添加到循环中(或者重新启动循环)。你能澄清一下你是否尝试过,你能用各种错误检查方法的信息来完成这个问题吗?我想我会尝试重新启动循环——它不会添加,因为它知道它已经存在。NOTIFY上的“连接”预期会返回一个未来,我不知道该怎么办……此处剽窃: