IRCのデータをソケットから読み出すには?

[上に] [前に] [次に]
tre 1999/04/18(日) 02:32:54
はじめまして。

 ただ今僕は、IRCのボットをPerlで書いています。
ですが、ソケットのファイルハンドルから値を取ることが出来なくて困っています。

簡単なソース、

S <- Socketのファイルハンドル。
print S "NICK bot\r\n";
$_ = scalar <S>;
print "Nickname is already in use\n" if (/433/); #433は、同一のニックネーム
があった時に出される。

ここで、ソケットのファイルハンドルに値がないと、ずっと待ってしまって、
IRCサーバからクローズされてしまいます。
どうにかして、エラーでなければundefを得たいのです。
やり方がわかりません。

よろしくお願いします。

B-Cus 1999/04/18(日) 07:39:16
IRCのプロトコルは全く知りませんが、

> ここで、ソケットのファイルハンドルに値がないと、ずっと待ってしまって、

"NICK bot\r\n" を送った後、サーバは
 「成功なら何も返さない」
 「失敗したら433を返す」
という動作をするんでしょうか。多分そういうことはなくて
 「成功したらxxxを返す」
という挙動をするんですよね?

なら、サーバが何も返さない原因は、クライアントが
正しいプロトコルをしゃべってないからではないでしょうか。

タトなら失礼。

tre [E-Mail] 1999/04/18(日) 07:47:16
B-Cusさんに返信してもらえて、、とてもうれしいです。
>「成功したらxxxを返す」
>という挙動をするんですよね?
成功したなら、何も返さないです。
だから、ずーっと待ってしまって・・
タイムアウトの処理の仕方とか、、ないでしょうか?

B-Cus 1999/04/18(日) 08:00:37
> 成功したなら、何も返さないです。

ほんとにほんとですか? もっかいRFC(などの解説文)を読んでみては
どうでしょうか。

普通、返事を返すかもしれないし、もしかしたら返さないかも
しれないサーバを相手にすることはできない…んじゃないかなぁと
思うんですが…(弱気)。
# ここらへんご存知の方、教えてください。

例えばFTP/HTTP/SMTPなど、いずれのプロトコルでも、返事が返って
くるかどうかわからない状況というのは発生しないですよね。


もしほんとに、成功したら何も返さないのなら、
 1. NICKの後に何か適当なプロトコル(常に返事が返ってくるもの)を送る
 2. ソケットから1行読んで、433ならNICKが失敗したということ
 3. 433じゃなくて、適当なプロトコルに対する返事が返ってきたら、
   NICKは成功したということ。
とか。でも何か正しい方法があるはず、と思います。

tre [E-Mail] 1999/04/18(日) 09:45:40
[[解決]]
もう一度、RFCをよく読んでみます。

>1. NICKの後に何か適当なプロトコル(常に返事が返ってくるもの)を送る
 >2. ソケットから1行読んで、433ならNICKが失敗したということ
こんなこと、思いつきませんでした。
早速、やってみます。

ついでに、
:[nickname]!~[name]@[ip address] [command] [channel or nickname] :[message]
*[]は、実際にはない。
ircでは、こんなふうにメッセージのやりとりがされています。

僕は、
if (/^:(.*)\?!~.*?\@(.*) (.*) :(.*)$/) {
    $nick = $1; $ip = $2; $command = $3; $msg_or_ch = $4;
    ....
#joinしてきた場合は、
#:nickname!~name@ip join :channel になる。

このような正規表現で、値を得ています。
もっと、スマートな書き方があったら教えて頂けませんか?

乱文で、ごめんなさい。

tre [E-Mail] 1999/04/18(日) 16:42:55
前に書いた正規表現では、対処できなくなったので、
こちらの方を教えてください。

$priv = ':tre!~user\@echna.ne.jp privmsg #channel :hello\n';
$join = ':nick!~user\@xxx.orange.ne.jp join :#channel\n';
を、一回でマッチさせたいんです。
$nameには、treまたは、nick.
$ipには、echna.ne.jpまたは、xxx.orange.ne.jp
$commandには、privmsgまたは、join
$channelには、#channelまたは、undef
$msg_or_chには、helloまたは、#channel

いろいろ考えて、
if (/^:(.*)?\!~.*?\@(.*) ([\w|\s]+)(.*) :(.*)$/) {
 $name = $1; $ip = $2; $command = $3; $channel = $4; $chMsg = $5;
}
のようにしてみましたが、ゴミが入ってしまいうまく動作しません。
たすけてください。。

B-Cus 1999/04/18(日) 21:00:05
解決マークを押されてますが、僕はIRCプロトコルを全く知らない
人間なので、あまり信用しないでね。


 $priv = ':tre!~user@echna.ne.jp privmsg #channel :hello';
 $join = ':nick!~user@xxx.orange.ne.jp join :#channel';
 /^:(.*?)\!~.*?\@(.*?) (\w+) ?(.*?)? :(.*?)$/

で如何。''内はエスケープ不要なので、\を書くとそのまま\として
認識されますのでご注意を。

まぁ正規表現でわからなくなったら、とりあえず$nameだけマッチ
させてみる、次に$ip、更に$commandも…というふうに一歩ずつ
やってけば必ずできます。実際 僕もそうやりましたし。

tre [E-Mail] 1999/04/19(月) 01:10:24
本当にありがとうございました。
もっと勉強しときます。。

これで、本当に解決ですね・・

[上に] [前に] [次に]