2

私は現在 IRC ボットを書いています。スクリプトは Perl モジュールとしてZNCにロードされますが、フォークされたプロセスを作成すると、入出力エラーでボットが切断されます。これは fork を使用しないスクリプトの例ですが、これにより、スクリプトがタスクを完了するまでボットがフリーズします。

package imdb;

use warnings;
use strict;


sub new
{
 my ($class) = @_;
 my $self = {};

 bless( $self, $class );
 return( $self );
}

sub OnChanMsg 
{
 my ($self, $nick, $channel,$text) = @_;

#unless (my $pid = fork()) {

 my $result = a_slow_process($text); 
 ZNC::PutIRC( "PRIVMSG $channel :$result" );
# exit;
#}

 return( ZNC::CONTINUE );

}

sub OnShutdown
{
 my ( $me ) = @_;
}

sub a_slow_process { 
my $input = shift; 
sleep 10; 
return "You said $input.";
 }

1;

エラーの原因となっている fork コードはコメントアウトされています。これを修正するにはどうすればよいですか?

追加するために編集: ZNC::PutIRC を子プロセスに入れるべきではないと言われました。

4

2 に答える 2

2

fork()呼び出しは、開いているファイルとソケット ハンドルに次のような影響を与えます。

ファイル記述子 (および場合によってはそれらの記述子のロック) は共有され、他のすべてはコピーされます。

...

v5.6.0 から、Perl は子プロセスをフォークする前に、出力用に開かれたすべてのファイルをフラッシュしようとしますが、これは一部のプラットフォームではサポートされていない場合があります (perlport を参照)。安全のために、 $| を設定する必要があるかもしれません (英語では $AUTOFLUSH) または、開いているハンドルで "IO::Handle" の "autoflush()" メソッドを呼び出して、出力の重複を回避します。

一般に、1 つのプロセスでソケット接続をセットアップし、子プロセスでその接続で読み取り/書き込みを試みることはお勧めできません。

回避策は、子プロセスで新しい ZNC 接続を作成し (完了後にa_slow_process())、プライベート メッセージを書き込んでから、新しい接続を閉じることです。

于 2010-05-14T01:48:49.353 に答える
0

モジュールを c++ で書き直すことに反対でなければ、znc には popen2() をラップする CExecSock があり、必要なことを行う必要があります。使用例については、shell.cpp モジュールを参照してください。

于 2010-11-17T17:58:43.783 に答える