socket->recv()和<>有什么区别?

6
我是一名有用的助手,可以为您翻译文本。

我正在尝试完成一个小型Perl学习项目,需要从套接字中读取4个无符号整数。我只能读取1个整数,经过挖掘后我找到了一个解决方案。但我需要理解我做错了什么(已经查阅了几本Perl书籍、perldocs等,但没有找到答案)。

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

{
  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)是“SIZE”参数默认为“bytes”,而整数为4个字节?

任何帮助、指导等都将不胜感激。顺便说一下,“学习项目”是overthewire.org - 非常酷。


1
为了简化文档,让我们先来介绍一下:perlvar $/<>只是readline的另一个名称。 - daxim
3个回答

5

你的套接字是TCP还是UDP?

recv<> / readline 更底层。它基本上直接映射到 recv(2) 系统调用。如果套接字数据作为 4 个 4 字节包到达,recv 会立即返回一旦它看到第一个包,即使已提供了更大的缓冲区。如果在第一次调用 recv() 之前所有 4 个数据包都到达,则您获取所有数据或仅获取一个片段的可能性取决于它是 TCP 还是 UDP。

如果使用的是 TCP,则存在数据包在传输过程中被分段的可能性。虽然使用 16 字节有效载荷不太可能发生这种情况,但最佳实践是不要假定即使您知道服务器一次发送了所有数据,也会同时显示 16 字节的数据。通常预期网络应用程序将缓冲传入的数据,或者您可以通过指定 16 字节记录来让 Perl 为您执行此操作:$/ = \16

另一个可能性,我认为对于这种 I/O 用法比 <> 更自然的方法是使用 readsysread 函数(或其面向对象的等效函数,定义在 IO::Handle 超类 IO::Socket 中)。它们需要一个长度参数,但同样,您不应假定整个缓冲区将一次填满。


2

关于1)

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

特殊变量$/是记录分隔符,默认为“\n”。您可以将其undef并一次读取整个文件(称为slurping)。有关更多信息,请参见perldoc perlvar(其中还有\number的情况)。


这对我有用,尽管我没有使用所有的注释。我从来没有能够让read/readline/recv工作。但现在我明白了如何使用<>和$/,我很舒适地继续前进。感谢您的帮助。 - 1111000110

1

readreadline(又名<>)在返回之前等待请求的字符数可用。仅在出现错误或EOF的情况下返回较少的字符,在这种情况下,下一次读取将返回错误或EOF。

sysread只要有一些字符可用就会立即返回,即使少于请求的数量。

根据您所说的,recv就像sysread。如果您想要16个字符,您必须循环直到拥有16个字符或使用readreadline


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接