如何在Perl Socket编程中在网络级别设置消息头

fv2wmkja  于 2022-11-24  发布在  Perl
关注(0)|答案(1)|浏览(317)

我有一个关于通过TCP/IP协议发送套接字数据到另一方/服务器的需求,其中一个核心需求是在消息头中设置消息长度。我们可以在Perl套接字编程中设置这样的操作吗?
我在PHP语言中看到了一个参考,其中消息长度可以按照示例https://www.php.net/manual/en/sockets.examples.php中的描述发送,如果Perl中有前面的内容,这将是很有帮助的。
我用Socket、IO::Socket::INET模块进行了验证,但几乎找不到与此相关的任何内容

nnsrf1az

nnsrf1az1#

了解您的需求

对于TCP等流协议,需要将信息插入流中,以允许读取器将流拆分为单独的消息。
它可以像在消息之间插入换行符一样简单。这是你链接到的示例所使用的方法。与你的说法相反,发送者在这些示例中没有提供消息的长度。[1]
这种方法的问题是换行符不能作为消息的一部分出现,可以引入转义机制,但这会减慢阅读。
另一个非常常见的方法是发送长度前缀。这是指在消息之前的某种头中发送消息的长度。从流中阅读消息包括首先读取头,确定消息的大小,然后读取消息的其余部分。
这就是你选择的方法。

发送和接收带长度前缀的消息

以下发件人使用此技术:
第一个
这些相同的片段在消息的长度之前(作为一个32位BE整数)。读取器将从阅读长度开始。有了这些信息,它知道需要读取多少才能获得完整的消息。因此,相应的读取器可能如下所示:[2]

my $buf = '';
while ( 1 ) {
   my $n = read_uint32be( $sock, $buf );
   die $! if !defined( $n );

   my $msg = read_exactly( $sock, $buf, $n );
   die $! if !defined( $msg );

   ...
}

1.而且读取器是有缺陷的,依赖于完全虚假的假设,即socket_read将只返回一行。
1.借助此功能:

use Errno qw( ENODATA );

use constant CHUNCK_SIZE => 64 * 1024;

# Returns `undef` and sets `$!` to `ENODATA` on eof.
# Returns `undef` and sets `$!` on error.
sub read_exactly {
   my $fh      =  shift;
   my $buf_ref = \shift;
   my $n       =  shift;

   $$buf_ref //= '';

   my $to_read = $n - length( $$buf_ref );
   while ( $to_read > 0 ) {
      my $rv = sysread( $fh, $$buf_ref, CHUNK_SIZE, length( $$buf_ref ) );
      if ( !$rv ) { 
         $! = ENODATA if defined( $rv );  # EOF
         return undef;
      }

      $to_read -= $rv;
   }

   return substr( $$buf_red, 0, $n );
}

# Returns `undef` and sets `$!` to `ENODATA` on eof.
# Returns `undef` and sets `$!` on error.
sub read_uint32be {
   my $packed = read_exactly( $_[0], $_[1], 4 );
   return undef if !defined( $packed );
   return unpack( "N", $packed );
}

相关问题