当数据长度未知时,从Perl中的套接字接收数据的最佳方法是什么?

现在,我在一个循环中一次读取一个字符,直到我达到
字符。有一个更好的方法吗?     
已邀请:
将行结束设置为
x{00}
( 0),确保将其本地化,并在句柄上设置
getline
,如下所示:
{
    local $/ = "x{00}";
    while (my $line = $sock->getline) {
       print "$linen"; # do whatever with your data here
   }
}
    
  当数据长度未知时,从Perl中的套接字接收数据的最佳方法是什么? 用任何语言都无法解决这个问题。如果您不知道数据长度是多长,那么您无法知道何时从套接字接收完所有数据。 您唯一的希望是使用某种度量来确定数据是否已经“足够长”,因为数据开始进入,以确定数据流已经停止。但它不会是完美的。     
答案取决于协议。由于你的协议使用' 0'作为分隔符,你做的是正确的。我很确定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=$lengthn";
}
样品运行: $ ./howmuch 39 得到:[SSH-2.0-OpenSSH_5.3p1 Debian-3ubuntu4 r n],长度= 39 但您可能更喜欢使用
IO::Socket::INET
IO::Select
模块,如下面的代码与Google交谈:
#! /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 = "1512";
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=$lengthn";
输出: 573 得到:[HTTP / 1.0 200 OK r n日期:Sun,2010年7月18日12:03:48 GMT r nExpires:-1 r nCache-Control:private,max-age = 0 r nContent-输入:text / html; charset = ISO-8859-1 r nSet-Cookie:PREF = ID = 6742ab80dd810a95:TM = 1279454628:LM = 1279454628:S = ewNg64020FbnGzHR; expires = Tue,17-Jul-2012 12:03:48 GMT;路径= /; domain = .google.com r nSet-Cookie:NID = 36 = kn2wtTD4UJ3MYYQ5uvA4iAsrS2wcrb_W781pZ1hrVUhUDHrIJTMg_kOgVKhjQnO5SM6MdC_jrRdxFRyXwyyv5N3Xja1ydhVLWWaYqpMHQOmGVi2K5qRWAKwDhCVRd8WS;到期=周一,2011年1月17日12:03:48 GMT;路径= /;域= .google.com; HttpOnly r n服务器:gws r nX-XSS-Protection:1; mode = block r n r n],长度= 573     
您可以使用
sysread
读取可用的数据:
my $data;
my $max_length = 1000000;
sysread $sock, $data, $max_length;
Perl的
read
函数等待您请求的完整字节数或EOF。 这类似于libcs​​tdio
fread(3)
。 Perl的
sysread
函数在收到任何数据后立即返回。 这类似于UNIX
read(2)
。 请注意,
sysread
绕过缓冲IO,因此不要将其与缓冲的
read
混合使用。 查看
perldoc -f read
perldoc -f sysread
了解更多信息。 对于这个特定的问题,最好按照最佳答案,并使用
getline
的行结尾为
,但如果没有终止字符,我们可以使用
sysread
。 这是一个小例子。它请求一个网页,并打印收到的第一个数据块。
#!/usr/bin/perl -w
use strict; use warnings;
use IO::Socket;

my $host = $ARGV[0] || 'google.com';
my $port = $ARGV[1] || 80;
my $sock = IO::Socket::INET->new(Proto => 'tcp', PeerAddr => $host, PeerPort => $port)
    or die "connect failed: $!";
$sock->autoflush(1);
# use HTTP/1.1, which keeps the socket open by default
$sock->print("GET / HTTP/1.1rnHost: $hostrnrn");
my $reply;
my $max_length = 1000000;
# $sock->read($reply, $max_length);   # read would hang waiting for 1000000 bytes
my $count = $sock->sysread($reply, $max_length);
if (!defined $count) {
    die "read failed: $!";
}
print $reply;
    

要回复问题请先登录注册