現在、文字に到達するまで、ループで一度に 1 文字ずつ読み取ります\0
。これを行うより良い方法はありますか?
5 に答える
行末を\x{00}
(\0) に設定し、必ずローカライズして、getline
次のようにハンドルに設定します。
{
local $/ = "\x{00}";
while (my $line = $sock->getline) {
print "$line\n"; # do whatever with your data here
}
}
答えはプロトコルによって異なります。プロトコルは区切り文字として「\0」を使用しているため、正しいことを行っています。Perlがバッファリングを処理すると確信しているので、一度に1文字ずつ読み取るのは非効率的ではありません。
多くのネットワーク指向プロトコルは、文字列の前に長さがあります。このようなプロトコルを読み取るには、長さ(通常、プロトコルの仕様に応じて1バイトまたは2バイト)を読み取り、その数のバイトを文字列に読み込みます。
データ長が不明な場合、Perl でソケットからデータを受信する最良の方法は何ですか?
これに対する健全な解決策は、どの言語でも不可能です。データの長さがどれくらいかわからない場合、ソケットからすべてのデータをいつ受信し終わったかを知ることはできません。
唯一の希望は、何らかのメトリックを使用して、データが入り始めてから「十分な時間」が経過したかどうかを判断し、データ フローが停止したと判断することです。しかし、それは完璧ではありません。
FIONREAD
で使用できますioctl
。以下のプログラムは、localhost の SSH サーバーに接続し、挨拶を待ちます。
#! /usr/bin/perl
use warnings;
use strict;
use subs 'FIONREAD';
require "sys/ioctl.ph";
use Socket;
socket my $s, PF_INET, SOCK_STREAM, getprotobyname "tcp"
or die "$0: socket: $!";
connect $s, sockaddr_in 22, inet_aton "localhost"
or die "$0: connect: $!";
my $rin = "";
vec($rin, fileno($s), 1) = 1;
my $nfound = select my$rout=$rin, "", "", undef;
die "$0: select: $!" if $nfound < 0;
if ($nfound) {
my $size = pack "L", 0;
ioctl $s, FIONREAD, $size
or die "$0: ioctl: $!";
print unpack("L", $size), "\n";
sysread $s, my $buf, unpack "L", $size
or die "$0: sysread: $!";
my $length = length $buf;
$buf =~ s/\r/\\r/g;
$buf =~ s/\n/\\n/g;
print "got: [$buf], length=$length\n";
}
サンプルラン:
$ ./いくら 39 取得: [SSH-2.0-OpenSSH_5.3p1 Debian-3ubuntu4\r\n]、長さ = 39
しかし、Google と通信する以下のコードのように、モジュールIO::Socket::INET
とモジュールを使用することをお勧めします。IO::Select
#! /usr/bin/perl
use warnings;
use strict;
use subs "FIONREAD";
require "sys/ioctl.ph";
use IO::Select;
use IO::Socket::INET;
my $s = IO::Socket::INET->new(PeerAddr => "google.com:80")
or die "$0: can't connect: $@";
my $CRLF = "\015\012";
print $s "HEAD / HTTP/1.0$CRLF$CRLF" or warn "$0: print: $!";
my @ready = IO::Select->new($s)->can_read;
die "$0: umm..." unless $s == $ready[0];
my $size = pack "L", 0;
ioctl $s, FIONREAD, $size
or die "$0: ioctl: $!";
print unpack("L", $size), "\n";
sysread $s, my $buf, unpack "L", $size
or die "$0: sysread: $!";
my $length = length $buf;
$buf =~ s/\r/\\r/g;
$buf =~ s/\n/\\n/g;
print "got: [$buf], length=$length\n";
出力:
573 取得: [HTTP/1.0 200 OK\r\n日付: 2010 年 7 月 18 日 (日) 12:03:48 GMT\r\n有効期限: -1\r\nキャッシュ制御: プライベート、最大年齢 = 0\r\nContent-タイプ: テキスト/html; charset=ISO-8859-1\r\nSet-Cookie: PREF=ID=6742ab80dd810a95:TM=1279454628:LM=1279454628:S=ewNg64020FbnGzHR; expires=2012 年 7 月 17 日火曜日 12:03:48 GMT; パス=/; domain=.google.com\r\nSet-Cookie: NID=36=kn2wtTD4UJ3MYYQ5uvA4iAsrS2wcrb_W781pZ1hrVUhUDHrIJTMg_kOgVKhjQnO5SM6MdC_jrRdxFRyXwyyv5N3Xja1ydhVLWSWWaYqpMHQOmGVi2K5qRWAKwDhCVR expires=Mon, 17-Jan-2011 12:03:48 GMT; パス=/; ドメイン=.google.com; HttpOnly\r\nサーバー: gws\r\nX-XSS-Protection: 1; モード=ブロック\r\n\r\n]、長さ=573