Perl IO::Socket::INET“;发送:无法确定对等地址“;
我有以下Perl代码片段: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-&
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,但如果你没有同伴可以发送,那也没关系。