Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Perl IO::Socket::INET“;发送:无法确定对等地址“;_Perl_Sockets - Fatal编程技术网

Perl IO::Socket::INET“;发送:无法确定对等地址“;

Perl IO::Socket::INET“;发送:无法确定对等地址“;,perl,sockets,Perl,Sockets,我有以下Perl代码片段: my $serverSocket = new IO::Socket::INET( LocalPort => 53, Proto => 'udp', ReuseAddr => 1, ) or Error("Could't open server socket."); print "Server started.\n"; my $clientQuery; while (1) { $serverSocket-&

我有以下Perl代码片段:

my $serverSocket = new IO::Socket::INET(
    LocalPort  => 53,
    Proto      => 'udp',
    ReuseAddr  => 1,
) or Error("Could't open server socket.");
print "Server started.\n";
my $clientQuery;
while (1) {
    $serverSocket->recv($clientQuery, 1024, 0);
    my $clientQueryParsed = IncomingDNSPacket::parseDNSPacket($clientQuery);
    my @questions = @{ $clientQueryParsed->{questions} };
    my @answers = map {getAnswer($_, $forwarder)} @questions;
    my $errorCode = @answers == 0 ? 3 : '';
    my $clientResponseParsed = {
        errorCode     => $errorCode,
        id            => $clientQueryParsed->{id},
        questions     => \@questions,
        answerRRs     => \@answers,
        additionalRRs => [],
        authorityRRs  => [],
    };
    my $clientResponse = OutgoingDNSPacket::makeAnswer(%$clientResponseParsed);
    $serverSocket->send($clientResponse, 0);
}
有时
$serverSocket->send($clientResponse,0)
返回此错误:
send:无法确定对等地址
。我试着用谷歌搜索它,发现若远程主机关闭了套接字,这种情况可能会发生。但这不是TCP,这是UDP。为什么会出现这个错误

编辑:这里是
getAnswer
的代码:

sub getAnswer {
    my $question = shift;
    my $forwarder = shift;
    my @answer;
    @answer = $cache -> get($question);
    if (@answer == 0) {
        my $forwarderPacket = getAnswerFromForwarder($question);
        $cache -> add ($forwarderPacket);
        @answer = $cache -> get($question);
    }
    return @answer;
}

sub getAnswerFromForwarder {
    my $question = shift;
    my $forwQuery = OutgoingDNSPacket::makeQuestion(id => 0, questions => [$question]);
    my $forwSock = new IO::Socket::INET (
            PeerAddr => $forwarder,
            PeerPort => 53,
            Proto => 'udp'
        ) or Error("Couldn't create forwarder socket");
    $forwSock -> send($forwQuery, 0);
    my $select = new IO::Select;
    $select -> add ($forwSock);
    my @socks = $select -> can_read(2);
    if (@socks > 0) {
        my $forwAnswer;
        $forwSock -> recv($forwAnswer, 1024, 0);
        my $forwUnpacked = IncomingDNSPacket::parseDNSPacket($forwAnswer);
        return $forwUnpacked;
    } else {
        return {
            errorCode => 3,
            questions => [],
            answerRRs => [],
            authorityRRs => [],
            additionalRRs => []
            };
    }
}

$forwSock
发送可能不成功。如果失败,我将无法从
$serverSocket
发送任何内容。为什么?简短的回答

use Errno;    # for %!
#use caution; this is untested and not thoroughly thought through

while (1) {
  my $ok = $udpSocket->recv($buf, $len, 0);
  if (! $ok) {
    redo if $!{ECONNREFUSED};  # Error from a previous UDP send
    die "recv: $!\n";
  }

  ...

  do {
    $ok = $udpSocket->send($buf, 0);
  } while (! $ok and $!{ECONNREFUSED});
}
您的问题是您没有处理
$udpSocket->recv(…)
错误,这会混淆您以后的
发送

最有可能的是,
recv
在ECONREFUNCE时失败。您希望忽略此错误并重试,并对
send
调用执行相同的操作

更长的答案

use Errno;    # for %!
#use caution; this is untested and not thoroughly thought through

while (1) {
  my $ok = $udpSocket->recv($buf, $len, 0);
  if (! $ok) {
    redo if $!{ECONNREFUSED};  # Error from a previous UDP send
    die "recv: $!\n";
  }

  ...

  do {
    $ok = $udpSocket->send($buf, 0);
  } while (! $ok and $!{ECONNREFUSED});
}
为了澄清,您对
send
的调用不会返回错误“无法确定对等地址”-它与该消息一起出现

IO::Socket在成功调用
$IO\u Socket->recv()
后记住远程对等地址。此对等点是下一次调用
$io\u socket->send()
的隐式目标。然而,一个不成功的
recv
,没有留下任何可用的对等地址,下面的
send
只是
croak
s,因为缺少目的地

(您的代码没有阻塞,因为
recv
缓冲区
$clientQuery
在发生故障
recv
后未被修改。您正在再次处理以前的
recv
数据包。)

现在,由于这是UDP,潜在错误可能与先前失败的
发送有关。很可能您发送了一个数据报,ICMP“dest unreach”稍后返回,随后对套接字的
send
/
recv
调用将此报告为ECONREFUNCE

伪编码答案

use Errno;    # for %!
#use caution; this is untested and not thoroughly thought through

while (1) {
  my $ok = $udpSocket->recv($buf, $len, 0);
  if (! $ok) {
    redo if $!{ECONNREFUSED};  # Error from a previous UDP send
    die "recv: $!\n";
  }

  ...

  do {
    $ok = $udpSocket->send($buf, 0);
  } while (! $ok and $!{ECONNREFUSED});
}

服务器对每个连接处理一个命令(之后$serverSocket被销毁)。因此,客户端无法在不重新连接的情况下发送第二个命令(当您指定PeerAddr时,这在->new()中完成)。@ChankeyPathak PeerAddr?为什么这个bug不总是出现?有时它是可以的,但如果套接字被破坏,它就不应该是可以的。Tcpdump或wireshark可以查看实际情况。关于您的编辑,您如何知道另一个
send
不成功?你认为这与你原来的问题有什么关系?@pilcrow可能有这样的情况,我会以
$forwSock
的形式将数据包发送到封闭端口。但我可以在
$socket->send
call中指定发送数据包所需的地址和端口吗?@user23791,re:send with a destination,yes,但如果你没有同伴可以发送,那也没关系。