私自身、詳細な指示が大好きです。これは、それを読んでいる人が見逃されたすべてを知る必要がないことを意味します。 彼が既に知っていることを彼に見逃すことをお勧めします。 さらに、彼は何かについて誤った考えを持っているかもしれません。
さて、退屈しないように、この例は別のトピックicqと互換性があるため、icq-botを取得します。
手始めに、悪魔について。
win32でのperlの開発、さらにはfork関数をエミュレートする可能性もありますが、unixについてお話します。 とにかく、icqサーバーと通信するために必要なモジュールはwin32の下ではシャープ化されません。
簡単に言えば、UNIXでは、各実行可能プログラムは特定の番号を持つプロセスを生成します。 プログラムは他のプログラムを実行できます-この場合、それは親になり、起動されます-子。 親プログラムが動作を停止すると、子プログラムも動作を停止します。
同時に、icq-botは、どこから起動されたか、このプロセスを開始した別のプログラムが動作を停止したかどうかに関係なく、継続的に動作する必要があります。 たとえば、ボッシュを起動したbashを使用して、sshを介してサーバーにログインしました。 bashとsshの接続を閉じた後、ボットは何も起こらなかったように動作し続けるはずです。
fork関数はこの目的を果たし、親が起動された端末に関連付けられていない子プロセスを開始します。 次に、setsid関数を呼び出す必要があります。これにより、プロセスの分離が完了します。
これらのアクションの後、新生児デーモンは、良いデーモンになりたい場合、作業ディレクトリをルートディレクトリに変更する必要があります-マウント経由で接続されたパーティションから起動した場合。 そうしないと、パーティションはビジーになり、無効にすることはできません。
さらに、端末からの入力およびデーモンによる端末への出力は実行されないため、これらの標準チャネルをゼロにリダイレクトする必要があります。 ボットを監視する場合は、出力をログファイルにリダイレクトできます。
最も難しいステップは、fork関数を使用することです。 彼女はまったく同じプロセスをもう1つ作成します。 それらの唯一の違いは、最初のものは親であり、終了する必要があり、2番目は子であり、残る必要があるということです。 したがって、プロセスには自己識別が必要です-私は誰ですか?
これは、fork関数が返す結果を確認することで実現されます。 ゼロ以外の値を返す場合、これは開始された新しい子プロセスのpidです。 だから私は親であり、去ります。 pidがゼロの場合、私は娘であり、仕事を続けています。
その結果、プロセスの悪魔化機能は次のとおりです。
sub Daemonize { <br/>
return if ( $^O eq 'MSWin32' ) ; # , <br/>
chdir '/' or die "Can't chdir to /: $!" ; # unmount <br/>
umask 0 ; # <br/>
open STDIN , '/dev/null' or die "Can't read /dev/null: $!" ; # <br/>
open STDOUT , '>/dev/null' or die "Can't write to /dev/null: $!" ; # <br/>
open STDERR , '>/dev/null' or die "Can't write to /dev/null: $!" ; # <br/>
defined ( my $pid = fork ) or die "Can't fork: $!" ; # fork <br/>
exit if $pid ; # , id <br/>
setsid or die "Can't start a new session: $!" ; # <br/>
} <br/>
メッセージ処理
理論上、ICQボットはいくつかのメッセージを送信し、受信したメッセージを処理する必要があります。 通知機能として動作するボットの簡単なバージョンを作成しましょう。システムからメッセージを受信する場所に送信し、受信メッセージに対する標準的な応答を提供します。 そして明確にするために、1つのコマンドの処理を行います-終了します。
そして、それはすべてあなたの想像力に依存します-あなたが好きなように着信メッセージを処理でき、ここであなたは多くの興味深いものを思い付くことができます-コマンドのシステム特性の発行から人工知能まで。
ファイルから配布するメッセージを受信する最も簡単な方法。 送信メッセージのあるファイル用に別のディレクトリを作成する必要があります。 メッセージを送信する必要があるプログラムは、このフォルダーにメッセージを保存します。
ボットは定期的にチェックする必要があり、新しいメッセージが見つかった場合は送信します。
これをやってみましょう-フォルダーにnnn.rrrという形式のファイルが作成されます。ここで、nnnは受信者のicq UIN、rrrは乱数です。これにより、複数のメッセージが一度に1つの数字になった場合にファイルが上書きされません。
合計-受信ボックスをスキャンし、各ファイルの内容をファイル名に示されている番号に送信する必要があります。
sub CheckTasks { <br/>
# <br/>
my ( $file , $path , $text , $size , $recipient ) ; <br/>
<br/>
$path = "~username/icq/icq_tasks" ; # <br/>
<br/>
opendir DIR , $path ; <br/>
for $file ( grep /^\d+\.\d+$/ , readdir DIR ) { # nnn.rrr <br/>
$file =~/^ ( \d + ) \ . \d + $/ ; <br/>
$recipient = $1 ; # - UIN <br/>
$size = ( stat ( "$path/$file" ) ) [ 7 ] ; <br/>
if ( $size > 0 && $size < 200 ) { # <br/>
$text = ReadFile ( "$path/$file" ) ; # <br/>
unlink ( "$path/$file" ) ; # <br/>
$oscar -> send_im ( $recipient , $text ) ; # . , oscar - <br/>
} <br/>
} <br/>
} <br/>
主なプログラム
ヘルパー関数、ほぼすべてを完了しました。 それでは、メインプログラムを作成しましょう。
ICQサーバーと対話するには、 Net :: OSCARモジュールを使用します。 これはオブジェクトモジュールです。そのため、サーバーに接続して通信するオブジェクトを作成し、サーバーが定期的にキックされて切断されないようにする必要があります。 さらに、接続の状態を確認し、中断した場合は再接続する必要があります。 そしてもちろん、メッセージを送受信します。
行こう:
#!/usr/bin/perl -w <br/>
<br/>
use Net :: OSCAR ; # <br/>
use strict ; # strict <br/>
use POSIX qw ( setsid ) ; # POSIX, <br/>
<br/>
Daemonize ( ) ; # <br/>
<br/>
my ( $UIN , $PASSWORD , $oscar , $t ) ; <br/>
<br/>
$UIN = '123456' ; # UIN <br/>
$PASSWORD = 'mypass' ; # UIN <br/>
<br/>
$oscar = Net :: OSCAR -> new ( ) ; # icq <br/>
$oscar -> set_callback_im_in ( \&send_answer ) ; <br/>
# - <br/>
$t = 0 ; # <br/>
<br/>
while ( 1 ) { # <br/>
if ( ! $oscar -> is_on && ( time ( ) - $t ) > 120 ) { # 2 ! <br/>
$oscar -> signon ( $UIN , $PASSWORD ) ; # <br/>
$t = time ( ) ; # <br/>
} <br/>
$oscar -> do_one_loop ( ) ; # <br/>
CheckTasks ( ) if ( $oscar -> is_on ) ; # - <br/>
sleep ( 5 ) ; # 5 , <br/>
}
いくつかのポイントについて詳しく説明します。
モジュールはイベントを処理します。イベントの1つは、着信メッセージの受信です。 ボットがそのようなメッセージへの回答を送信できるように、このイベントでsend_answer()関数の呼び出しを終了します。
$ oscar-> set_callback_im_in(\&send_answer)
次のようになります。
sub send_answer ( ) { <br/>
my ( $oscar , $sender , $msg ) = @_ ; <br/>
# - <br/>
# , <br/>
if ( $msg eq "quit" ) { # . - <br/>
$oscar -> signoff ( ) ; # <br/>
exit ( ) ; # - <br/>
} <br/>
$oscar -> send_im ( $sender , ' , , .' ) ; <br/>
# <br/>
}
sub send_answer ( ) { <br/>
my ( $oscar , $sender , $msg ) = @_ ; <br/>
# - <br/>
# , <br/>
if ( $msg eq "quit" ) { # . - <br/>
$oscar -> signoff ( ) ; # <br/>
exit ( ) ; # - <br/>
} <br/>
$oscar -> send_im ( $sender , ' , , .' ) ; <br/>
# <br/>
}
したがって、インバウンドハンドラーを作成し、アウトバウンド処理を無限ループで処理します。 オンラインかどうかを確認するには、$ oscar-> is_onフラグを使用します
また、接続要求で頻繁にハンマーを使用しないように、タイマーを使用します。最後の接続試行の時刻は$ tに保存されます。 特に、このセクションはプログラムの起動後に機能し、サーバーへの最初の接続を確立します。
オンラインの場合、定期的に$ oscar-> do_one_loop()メソッドを呼び出し、ボットのログインを維持します。
また、ネットワーク上にいる場合は、受信メッセージのフォルダーを確認し、必要に応じて送信します。
作成、保存、実行します。 最も簡単なicqボットの準備ができました! このようなボットを使用して、サーバーから通知を送信します。
今何?
このボットの欠点の中でも、Net :: OSCARモジュールはオフラインユーザーにメッセージを送信できないことに注意してください。
宿題として、以下を提案します。
-4番目-2分待つのではなく、最初の起動の直後にボットをicqに接続します
-4つのプラス記号付き-ReadFile関数を記述します
-5人-Net :: OSCARのドキュメントを理解し、メッセージの受信者がオフラインかどうかを判断し、メッセージをオフラインで送信しないようにボットに教えます。