为什么通过Perl Socket-> send()的sendto()忽略对等地址?

时间:2019-03-14 11:41:45

标签: perl sockets sendto

我有一个程序(这里太复杂了,无法使用),它使用由IO::Socket::INET->new()创建的UDP套接字,同时具有Local...Peer...的地址和端口。因此可以预期,普通的$sock->send($data, $flags)会将$data发送到创建套接字时指定的对等地址。似乎可行。

但是,当我尝试使用$sock->send($data, $flags, $dest)将单个数据包发送到不同的目的地时,$dest似乎被忽略了(并且该数据包被定向到套接字的对等地址)。我添加了许多调试消息,并且参数$dest已正确传递到send,但是strace显示{{1}被sendto()的{​​{1}}调用了}}和NULL代表sockaddr

0对我没有帮助。那么为什么目的地地址会被忽略?

根据要求,这是send_packet代码(有些冗长):

socklen

因此,显然目的地是作为“ 主机 端口”传递的(一个字符串不带空格(空格是由于标记不足在这里造成的)) )。

1 个答案:

答案 0 :(得分:2)

如果在创建Peer*时使用IO::Socket::INET,则将调用connect(),这将设置套接字的对等名称。在这样的套接字上,您不必指定远程套接字地址,因为它具有默认地址。

IO::Socket::send()具有“功能”:当套接字具有有效的对等名称时,它将忽略TO参数:

 my $r = defined(getpeername($sock))
     ? send($sock, $_[1], $flags)
     : send($sock, $_[1], $flags, $peer);

该更改是在IO 1.12中引入的,很遗憾,该更改早于当前git repository的历史:

  

修改了IO :: Socket :: send,所以不要传递4个参数来发送    如果插座已连接

如果您不喜欢这种行为,则必须使用原始的CORE::send(),即:

#!/usr/bin/perl
use warnings;
use strict;

use IO::Socket::INET;
use Socket qw(pack_sockaddr_in);

my $client = IO::Socket::INET->new(
    PeerAddr  => '127.0.0.1',
    PeerPort  => 2000,
    Proto      => 'udp',
) or die "client socket: $!\n";

my $addr = pack_sockaddr_in(2000, inet_aton('127.0.0.1'));

$client->send('ABCD', 0)
    or die "IO::Socket::send() no addr: $!\n";
$client->send('ABCD', 0, $addr)
    or die "IO::Socket::send() with addr: $!\n";
send($client, 'ABCD', 0, $addr)
    or die "send() with addr: $!\n";

exit 0;

试运行:

$ strace -e sendto,connect,socket perl dummy.pl
socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC, IPPROTO_UDP) = 4
connect(4, {sa_family=AF_INET, sin_port=htons(2000), sin_addr=inet_addr("127.0.0.1")}, 16) = 0
sendto(4, "ABCD", 4, 0, NULL, 0)        = 4
sendto(4, "ABCD", 4, 0, NULL, 0)        = 4
sendto(4, "ABCD", 4, 0, {sa_family=AF_INET, sin_port=htons(2000), sin_addr=inet_addr("127.0.0.1")}, 16) = 4

我的Linux机器上的跟踪表明send()已映射到sendto(),因为Perl代码确实调用了send() and sendto()


更新:我已经创建了upstream ticket #133936