6

我正在尝试完成一个需要从套接字读取 4 个无符号整数的小型 Perl 学习项目。我无法读取超过 1 个整数,在四处挖掘后我找到了解决方案。但我需要了解我做错了什么(并且已经阅读了几本 Perl 书籍、perldocs 等,但无济于事。)

示例 1:这是成功的解决方案代码(原始),假设以下两者的套接字连接都成功:

{
  local $/ = \16; # make <> read in 16 bytes with one swoop.
  my @integers = unpack "IIII", <$sock>;
  print "numbers: @val\n";
}

示例 2:我在下面尝试了这个。如果我在拆包之前打印输入,我只会得到一个整数:

my $input;
$sock->recv($input,16,0);
my @integers = unpack("IIII", $input);

具体问题:

  1. 在示例 1 中,“$/”到底是什么?它是如何“改变”<>,我认为它是 STDIN 的?
  2. 在示例 2 中,为什么我的 recv() 不会从套接字中取出一个以上的整数,是否有某种原因?我的理解(perldoc)是“大小”参数默认为“字节”,整数是 4 个字节?

任何帮助,指针等表示赞赏。顺便说一句,“学习项目”是 overthewire.org - 很酷的东西。

4

3 回答 3

5

你的套接字是 TCP 还是 UDP?

recv是比<>/更低级别的例程readline。它或多或少直接映射到recv(2)系统调用。如果套接字数据以 4 个 4 字节数据包的形式到达,recv则在看到第一个数据包后立即返回,即使已为其提供了更大的缓冲区。如果所有 4 个数据包都在第一次调用之前到达recv(),那么您是获得所有数据还是仅获得一个数据可能取决于它是 TCP 还是 UDP。

如果您使用 TCP,则数据包可能会在传输过程中被分段。16 字节的有效负载不太可能发生这种情况,但最佳实践是不要假设 16 字节的数据会一次全部显示,即使您知道服务器一次发送了所有数据。网络应用程序通常需要缓冲传入的数据,或者,您可以让 perl 为您做这件事,方法是指定 16 字节的记录$/ = \16

我发现比<>这种 I/O 用法更自然的另一种可能性是使用reador函数(或在超类sysread中定义的 OO 等效项)。那些需要一个长度参数,但和以前一样,您不应该假设整个缓冲区将立即被填充。IO::SocketIO::Handle

于 2011-04-08T21:15:26.043 回答
2

至于1)

好吧,<>接受任何文件句柄,包括套接字。这是一个约定,您可以将其留空,在这种情况下,假定某种合理的默认行为。见perldoc perlop(在里面搜索<>)。

特殊变量$/是记录分隔符,默认为“\n”。您可以取消定义并一次读取整个文件(这称为 slurping)。查看perldoc perlvar更多信息(\number案例也在那里)。

于 2011-04-08T19:49:57.643 回答
1

read并且readline(又名<>)在返回之前等待请求的字符数量可用。如果发生错误或 EOF,它只会返回更少的字符,在这种情况下,下一次读取将返回错误或 EOF。

sysread一些字符可用时立即返回,即使少于请求的数量也是如此。

根据你所说的,recv就像sysread。如果需要 16 个字符,则必须循环直到有 16 个字符或使用reador readline

于 2011-04-09T05:08:43.103 回答