2017-09-07 56 views
1

對於我來說,我似乎無法弄清楚如何獲得一個標準的TCP套接字連接後重新連接斷開,尤其是在IO ::異步::環Perl IO :: Socket :: INET + IO :: Async :: Stream在斷開連接時重新連接到TCP服務器

一些基本的方面:

#!/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"); 

在現實中,有很多事情在循環回事。我還有更復雜的方法來測試socket關閉或中斷,$ notifystream上的更多錯誤處理程序,以及重新連接到遠程服務的更好的超時/退避,但是這應該顯示我正在做的主要關鍵。

當遠程服務器由於任何原因而離開時,我想嘗試重新連接它而不會中斷系統的其他部分。在大多數情況下,遠程發送eof乾淨,因爲它有意重新啓動(不是我的選擇,只是我必須處理),但我也想處理其他通信錯誤。

在實踐中,上述代碼的工作方式就像它的工作原理一樣,但遠程服務不再接收對$ notifystream的進一步寫入調用。沒有錯誤產生,$ notifystream愉快地進一步寫入,但他們不被傳送到遠程。

我有一種感覺,我做錯了。我不打算重寫應用程序事件循環的其餘部分,所以請不要'只使用AnyEvent'類型的響應 - 真正希望更好地瞭解如何重新連接/重用/重新創建使用的變量(IO :: Socket :: INET和IO :: Async :: Stream)來補償遠程服務器暫時不可用時的情況。

歡迎對此目標提出任何建議或參考。謝謝!

- = - = - = - = -

總結錯誤我有(並且沒有)接收: 如果我不留usleep,基座插座由於將失敗的重新連接(或娛樂)遠程服務不可用。 如果我試圖從頭開始重新創建套接字,然後'配置'流,我得到'不能調用未定義的方法sysread這導致我相信套接字沒有正確重新創建。 在任何時候,無論我使用當前代碼寫入套接字的時間多少,流的內置'on_read_error'或'on_write_error'處理程序都會觸發,但如果我完全銷燬套接字,則會生成一個錯誤。 套接字似乎仍然是活躍的,我知道它已經關閉,重新連接似乎並沒有改變任何東西。沒有錯誤產生,但套接字沒有被寫入。

是否有不同的語法重新連接到一個IO ::套接字:: INET套接字?到目前爲止,調用connect()或重新開始重建似乎是關閉連接的唯一選項,並且都不起作用。

+0

我沒有看到任何錯誤檢查?你提到你有他們,他們說什麼?你肯定需要「重新啓用」重新啓動,這些錯誤將有助於弄清楚什麼。 – zdim

+0

我在IO :: Async :: Stream中有'on_read_error','on_write_error'和'on_writeable_stop' - 它們都沒有觸發。在所有。我也試過/ catch'd所有 - 問題是沒有引發錯誤。它只是不起作用。 – derelict

+0

你嘗試重新連接你的'$ NOTIFY'嗎?這個問題還不清楚。你可能也可能不需要再向環路添加'(也許重新啓動它)。你能澄清你是否嘗試過,你能否用這些錯誤檢查方法所說的信息來完成這個問題? – zdim

回答

1

您根本無法多次連接現有的套接字。您只能關閉套接字並創建一個新的套接字。這與IO :: Socket :: INET,IO :: Async :: Stream甚至Perl無關,但這是套接字API的工作原理。

詳細信息:本地套接字實際上從未斷開連接,即它仍配置爲從特定本地IP地址和端口發送數據到特定地址和端口。只有這樣,發送將不再有效,因爲基礎TCP連接斷開或關閉(即FIN交換)。由於沒有API來解除綁定和解除連接,唯一的方法是關閉它並創建一個新的未綁定和未連接的連接,直到連接被調用。這個新的套接字可能會或可能不會獲得與前一個文件相同的文件描述符。

相關問題