Perl 套接字连接在外部主机上挂起

Perl socket connection hangs on external host

我有下面的程序,它建立套接字连接并只读回服务器的第一行 returns。它适用于我网络内的任何东西,但如果我尝试到外面去,它就会挂起并且什么都不做。即端口 25 上的 smtp.gmail.com。不确定它有什么问题,google 搜索没有给我太多信息。

use Socket;
use Net::Ping;

$remote = $ARGV[0];
$port = $ARGV[1];

my $p = Net::Ping->new();
if (!$p->ping($remote)) {
    print STDERR "Error: Invalid hostname\n";
    exit(1);
}

if ($port =~ /\D/) {
    $port = getservbyname($port, 'tcp')
}
if ($port > 65535 || $port < 0) {
    print STDERR "Error: Invalid port\n";
    exit(1);
}
$iaddr = inet_aton($remote);
$paddr = sockaddr_in($port, $iaddr);
$proto = getprotobyname('tcp');
socket(SOCK, PF_INET, SOCK_STREAM, $proto);
connect(SOCK, $paddr);
$line = <SOCK>;
print STDOUT "$line\n";
close(SOCK);

exit(0);

如有任何帮助,我们将不胜感激。

您的代码并没有真正的问题,只是您的假设有误。

您的假设是 Net::Ping 可用于查明主机是否有效,但此假设是错误的。 Net::Ping 默认情况下只是尝试向主机发送 ICMP 回显请求并期望返回 ICMP 回显响应。但是许多主机(如 smtp.gmail.com)不会回复此类请求,即使主机可能可以通过其他方式访问,例如通过 TCP 连接到特定端口,就像您接下来所做的那样。

我只是建议删除 Net::Ping 的这种用法。如果无法连接到主机,那么 connect 将失败,这应该足够了。但即使 connect 成功,您的代码也可能会挂起,因为您依赖服务器先发送一些数据。在 SMTP(端口 25)或 FTP(端口 21)等协议中,服务器将首先发送一些问候语,但在 HTTP(端口 80)等其他协议中,客户端应在服务器回复之前发送数据。在这些情况下,您的代码将挂起,因为它不发送任何数据,因此服务器只是挂起,等待正确的请求,然后再发送响应。

除此之外,我建议使用 IO::Socket::IP 而不是普通套接字。它不仅使代码更简单,而且可以透明地与 IPv6 一起工作。您的代码明确使用 inet_aton,因此仅适用于 IPv4。