4

現在、文字に到達するまで、ループで一度に 1 文字ずつ読み取ります\0。これを行うより良い方法はありますか?

4

5 に答える 5

6

行末を\x{00}(\0) に設定し、必ずローカライズして、getline次のようにハンドルに設定します。

{
    local $/ = "\x{00}";
    while (my $line = $sock->getline) {
       print "$line\n"; # do whatever with your data here
   }
}
于 2010-07-18T10:22:17.303 に答える
2

答えはプロトコルによって異なります。プロトコルは区切り文字として「\0」を使用しているため、正しいことを行っています。Perlがバッファリングを処理すると確信しているので、一度に1文字ずつ読み取るのは非効率的ではありません。

多くのネットワーク指向プロトコルは、文字列の前に長さがあります。このようなプロトコルを読み取るには、長さ(通常、プロトコルの仕様に応じて1バイトまたは2バイト)を読み取り、その数のバイトを文字列に読み込みます。

于 2010-07-18T09:30:58.573 に答える
2

データ長が不明な場合、Perl でソケットからデータを受信する最良の方法は何ですか?

これに対する健全な解決策は、どの言語でも不可能です。データの長さがどれくらいかわからない場合、ソケットからすべてのデータをいつ受信し終わったかを知ることはできません。

唯一の希望は、何らかのメトリックを使用して、データが入り始めてから「十分な時間」が経過したかどうかを判断し、データ フローが停止したと判断することです。しかし、それは完璧ではありません。

于 2010-07-18T09:16:54.917 に答える
2

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
于 2010-07-18T12:04:33.887 に答える