|
なるほど…だいたいよくわかりました、ありがとうございます。 でもまだget_domainサブルーチン中の処理がよくわかりませんねぇ…。 while文の最初のif文の中です。 493: if ( ( $len & 0xc0 ) == 0xc0 ){ 494: # 上位 2ビットが立っていたら、もう 1バイト読みこむ (合計 16ビット)。 495: # そして上位 2ビットを落とし、残り 14ビットを DNS サーバから 496: # 返された UDP データグラム先頭からのオフセットとして再帰。。 497: 498: my $offset = unpack('n', $data) ^ 0xc000; 499: my $new_data = substr($org_data, $offset); 500: substr($data, 0, 2) = ''; 501: 502: my ($domain_part) = get_domain($new_data, $org_data); 503: push(@domains, $domain_part); 504: last; 505: 506: } else { 507: # 上位 2ビットが立っていないので、カウンタとして扱う。 508: substr($data, 0, 1) = ''; 509: } まず、if文の中で$dataの上位2ビットが立っていたときに、その2ビットを除いた上位14ビットを$offsetに入れて、$org_dataの$offset番目からのデータを$new_dataに入れて、$dataの上位2ビットを落としたところまではわかりました。 そのあと再びget_domainサブルーチンを呼び出すところからが…どうなるのでしょうか??(^^; また、else文の中の1行はどういった意味を持っているのでしょうか? ここでいう「カウンタ」という物もよくわからなくて…。 どうか、よろしくお願いします |
|
>>3327 ken > そのあと再びget_domainサブルーチンを呼び出すところからが… > どうなるのでしょうか??(^^; http://x68000.startshop.co.jp/~68user/net/resolver-2.html#6 の例だと、 最初に get_domain が受け取った $data が (0x04)www2(0xC0)(0x13).... で、一回目の while ループが終了した時点で $data = "(0xC0)(0x13)...." @domains=('www2');★1 となっています。 二回目の while ループでは my $len = unpack('C', $data); で $len は 0xC0 になり、 if ( ( $len & 0xc0 ) == 0xc0 ){ が真なので my $offset = unpack('n', $data) ^ 0xc000; ⇒ $offset は 0x13 my $new_data = substr($org_data, $offset); ⇒ $new_data は、UDP データグラム全体 ($org_data) の 0x13バイト目 substr($data, 0, 2) = ''; ⇒ $data は "(0xC0)(0x13)...." から "...." となる (先頭 2バイトを削る) となります。$new_data には (0x09)startshop(0x02)co(0x02)jp(0x00) が入っています。 ここで my ($domain_part) = get_domain($new_data, $org_data);★2 push(@domains, $domain_part);★3 と get_domain を再帰呼び出しすると、 sub get_domain { my ($data, $org_data) = @_; の $data には (0x09)startshop(0x02)co(0x02)jp(0x00).... が入っています。再帰呼び出しされた get_domain が処理を終えるときには @domains = ('startshop', 'co', 'jp'); となっており、最終的に return 'startshop.co.jp'; とドメインの一部を返します。 で、再帰呼び出しした側の get_domain に処理が戻ると、以下のような 流れになります。 ★1 の @domains にはすでに www2 が入っている ★2 の $domain_part には、再帰呼び出しした get_domain から受け取った startshop.co.jp が入っている ★3 で @domains = ('www2', 'startshop.co.jp') となる > また、else文の中の1行はどういった意味を持っているのでしょうか? > ここでいう「カウンタ」という物もよくわからなくて…。 (0x03)www(0x02)jp(0x07)FreeBSD(0x03)org(0x00) の 3・2・7・3・0 がここでいうカウンタです。$len には その後に続くバイト長が入っており、 508: substr($data, 0, 1) = ''; はその $len の部分を削っています。 # 説明文で使用していない用語 (カウンタ) を、ソースで使ってはいけませんね。 |
|
先日質問させていただいた、tomtomです。 クライアントが受信待ちの状態の時に、サーバに ソケットをクローズされたら、クライアントは、 どうなるのでしょうか? 以前質問させていただいた時に、undefを受信してしまう という問題があったのですが、サーバ側で勝手にセッションを 終了してしまっていた可能性があるので、その辺が関係している かどうか疑問に思ったため、再度質問させていただきました。 |
|
あ〜っ、なるほど! わかりました!完璧にわかって疑問が紐解けましたよ〜! get_domainの再起呼び出し後はそういう処理だったんですね…。 カウンタの意味もわかりましたし(^^;)、もうばっちりです! 長々と本当にありがとうございましたm(_ _)m もしまた何かありましたら…よろしくお願いいたします(^^; |
|
こんにちは、今Perl で UDP 通信を行うスクリプトを作っているの ですが、少し分からないところがあるので質問させてください。 普通に UDP 通信は問題なく行えているのですが、送信元の IP アドレスが 拾えなくて悩んでおります。 recv 関数の戻り値で「送信元のアドレス」は拾えるのですが、送信元が 「どこへ宛てて送信したか?」が分からないのです。 IO::Socket::INET モジュールを使用していますが、peeraddr メソッドを 使っても何も返ってきません。 http://x68000.startshop.co.jp/~68user/net/udp-3.html に UDP で connect 出来ると書かれていますが、connect すれば送信先アドレスを 拾う事ができますでしょうか? ご存じの方、よろしくお願いいたします。 |
|
>>3329 tomtom > クライアントが受信待ちの状態の時に、サーバにソケットを > クローズされたら、クライアントは、どうなるのでしょうか? 単に相手がソケットをクローズしただけなら、recv は 0 を 返します。 もし A が listen → B が connect → A がソケットクローズ → B が send → B が recv なら、B は SIGPIPE を受けます。 >>3331 lopper > recv 関数の戻り値で「送信元のアドレス」は拾える > のですが、送信元が「どこへ宛てて送信したか?」が > 分からないのです。 ソケットが送信先を記憶していないからです。同じ相手に 連続して UDP データグラムを送信する場合、 socket(SOCKET, PF_INET, SOCK_DGRAM, 0); send(SOCKET, "hoge1", 0, $sock_addr); send(SOCKET, "hoge2", 0, $sock_addr); と、毎回 send の引数に宛先である $sock_addr を指定 しなければいけません。なぜなら、一度目の send を 実行した後、SOCKET は $sock_addr に送信したことを 覚えていないからです。 # ソケットの先のアドレスが確定していないので、相手側で # エラーがあって ICMP メッセージが返ってきても、カーネルは # どのソケットにエラーを伝えればよいかわからない。だから # 非 connect な UDP では相手側のエラーを拾えないわけです。 > connect すれば送信先アドレスを拾う事ができますでしょうか? できます。 socket(SOCKET, PF_INET, SOCK_DGRAM, 0); connect(SOCKET, $sock_addr); この処理で SOCKET は「宛先が $sock_addr であること」を 覚えます。よって、この後 send する場合は send(SOCKET, "hoge1", 0); と宛先を省略できるのです。 C で言うと、connect(2) することで、sendto(2) ではなく send(2) が使えるということです。 |