私の人生の間、標準のTCPソケット接続を取得して後で再接続する方法がわからない特にIO ::非同期の文脈で切断、::ループPerl IO ::ソケット:: INET + IO ::非同期::ストリーム切断時に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");
、ループ内で起こって、より多くのものがあります。また、$ notifystream上のソケットのクローズや壊れたエラーハンドラ、リモートサービスへの再接続のためのより良いタイムアウト/バックオフをテストするもっと洗練された方法がありますが、これは私がやっていることの主要な要点を示すはずです。
リモートサーバーが何らかの理由で遠ざかった場合は、システムの残りの部分を中断することなく再接続を試みたいと思います。ほとんどの場合、リモコンは意図的にリブートしているので、eofをきれいに送信します(私の選択ではなく、私が対処しなければならないもの)が、他の通信エラーも処理したいと思います。
実際には、上記のコードは動作するように動作しますが、リモートサービスは$ notifystreamへの書き込みコールをもう受信しません。エラーは生成されませんが、$ notifystreamはそれ以上の書き込みを喜んで行いますが、リモートには配信されません。
私はこれが間違っていると感じています。私はアプリケーションのイベントループの残りの部分を書き直すつもりはないので、「AnyEvent」タイプの応答を使用しないでください。実際にここで使用されている変数を再接続/再利用/再作成する方法をよりよく理解したいと思っています::ソケット:: INETとIO ::非同期::ストリーム)を使用して、リモートサーバーが一時的に使用できなくなったときにこれを補うことができます。
この目標に向けた提案や参考資料は大歓迎です。ありがとう!
- = - = - = - = -
私は(とされていない)受信エラー要約する:私ははusleep、に起因して失敗するベースソケットの再接続(又は娯楽)を残さない場合 をリモートサービスは利用できません。 ソケットをゼロから再作成してストリームを '設定'しようとすると、 'メソッドが定義されていないためsysreadを呼び出せません'というメッセージが表示され、ソケットが正しく再作成されません。 は、現在のコードでソケットに書き込む量に関係なく、ストリームのビルトインされた 'on_read_error'または 'on_write_error'ハンドラを起動しますが、ソケットを完全に破棄するとエラーが発生します。 ソケットが閉じていることを知ってもソケットはまだアクティブな状態にあるようですが、再接続しても何も変わらないようです。エラーは生成されませんが、ソケットは書き込まれません。
IO :: Socket :: INETソケットに再接続するための構文が異なりますか?これまでのところ、 - > connect()への呼び出しやゼロからの再ビルドはクローズド接続の唯一のオプションと思われ、いずれも動作していないようです。
エラーチェックはありませんか?あなたは彼らがいると言います、彼らは何を言いますか?あなたは確かに再起動の "再有効化"する必要があり、それらのエラーは何を把握するのに役立ちます。 – zdim
私はIO :: Async :: Streamの中で 'on_read_error'、 'on_write_error'と 'on_writeable_stop'を持っています。まったく。私も試してみた/ catch'd - 問題は何もエラーをスローされません。それだけでは動作しません。 – derelict
'$ NOTIFY'で再接続しようとしましたか?この質問からは不明です。また、ループに 'add'する必要があるかもしれませんし、再起動する必要もありません。あなたが試したかどうかを明確にすることができますか?さまざまなエラーチェック方法が何を言いますか? – zdim