Perl Net::SSLeay 检查套接字是否可读

Perl Net::SSLeay check if socket is available to read

我正在使用一个名为 Net::APNS::Persistent 的 perl 模块。它帮助我打开与苹果的 apns server 的持久连接并通过 APNS 发送推送通知。此模块使用 Net::SSLeay 与 APNS 服务器进行 ssl 通信。

现在,我想定期从我的套接字读取以检查 APNS 是否发回任何响应。 Net::APNS::Persistent 已经有一个名为 _read() 的函数,如下所示:

sub _read {
    my $self = shift;

    my ($socket, $ctx, $ssl) = @{$self->_connection};

    my $data = Net::SSLeay::ssl_read_all( $ssl );
    die_if_ssl_error("error reading from ssl connection: $!");

    return $data;
}

但是,此功能仅在 APNS 断开连接并且我在尝试写入时出错时才有效。在其他时候,我的脚本卡在了

my $data = Net::SSLeay::ssl_read_all( $ssl );

我查看了 Net::SSLeay 文档,发现它有一个名为 peek 的方法

Copies $max bytes from the specified $ssl into the returned value. In contrast to the Net::SSLeay::read() function, the data in the SSL buffer is unmodified after the SSL_peek() operation.

虽然它可能有用,但我在 Net::APNS::Persistent 模块中添加了另一个函数:

sub ssl_peek {
    my $self = shift;
    my ($socket, $ctx, $ssl) = @{$self->_connection};
    print "Peeking \n";
    my $data = Net::SSLeay::peek( $ssl, $pending );
    print "Done peeking \n";
    return $data;
}

不幸的是,这也给了我同样的问题。它只打印 Peeking 而永远不会到达打印 Done peeking 的行。使用 Net::SSLeay::read 时遇到同样的问题。有没有办法检查套接字是否可以读取或设置读取超时,以便我的脚本在尝试从套接字读取时不会卡住?

检查是否可以读取底层套接字使用select,即

 IO::Select->new(fileno($socket))->can_read(timeout);

超时可以是 0 只检查而不等待,可以是秒数或者可以是 undef 永远等待。但在执行 select 之前,请检查 SSL 缓冲区中的数据是否仍然可用:

 if (Net::SSLeay::pending($ssl)) { ... use SSL_peek or SSL_read ... }

除此之外,您使用的模块看起来确实没有尝试验证服务器证书:(

APNS documentation 表示如下:

If you send a notification that is accepted by APNs, nothing is returned.

If you send a notification that is malformed or otherwise unintelligible, APNs returns an error-response packet and closes the connection. Any notifications that you sent after the malformed notification using the same connection are discarded, and must be resent

只要您的通知被接受,就不会有任何数据要读取,因此对套接字的读取操作将被阻止。唯一可用的数据是出现错误时,然后连接立即关闭。这应该可以解释您观察到的行为。