Perl 5.32环境下Net::HTTP长连接读取超时问题排查求助
Perl 5.32.1 Docker环境下Net::HTTP长连接超时问题排查与修复
问题背景
在Docker容器中构建Perl 5.32.1环境时,安装libwww-perl遇到Net::HTTP测试用例失败的问题,通过强制安装Net::HTTP绕过了该问题。但后续编写的长连接测试脚本在Docker环境中执行时,第二次请求出现超时错误;而在桌面环境(Perl 5.30.2,Net::HTTP 6.22)中执行则完全正常。
Docker构建脚本
原始构建脚本如下(已标注需添加的强制安装Net::HTTP的行):
RUN curl -SL https://www.cpan.org/src/5.0/perl-5.32.1.tar.gz -o /opt/perl-5.32.1.tar.gz \ && tar -xvzf /opt/perl-5.32.1.tar.gz --directory /opt \ && cd /opt/perl-5.32.1 \ && ./Configure -de \ && make \ && make test \ && make install \ && rm -f /opt/perl-5.32.1.tar.gz \ && yes | cpan install App::cpanminus \ && yum install -y openssl \ && cpanm install -f Net::HTTP \ # 新增:强制安装Net::HTTP以绕过测试失败 && cpanm install OALDERS/libwww-perl-6.55.tar.gz \ && cpanm install OALDERS/LWP-Protocol-https-6.10.tar.gz \ && rm -Rf /opt/perl-5.32.1
测试脚本
用于验证长连接的Perl脚本:
use Net::HTTP; my $s = Net::HTTP->new(Host => "www.neverssl.com", KeepAlive => 1, Timeout => 15, PeerHTTPVersion => "1.1", MaxLineLength => 512) || die "$@"; for my $iter (1..2) { # 注意:此处有笔误,多了一个逗号,建议修正为 GET => "/", 'User-Agent' => ... $s->write_request(GET => "/",, 'User-Agent' => 'Mozilla/5.0', 'Accept-Language' => 'no,en', Accept => '*/*'); print "Reading response for request $iter.\n"; my ($code, $mess, %h) = $s->read_response_headers; print "# --------------------\n"; print "# $code $mess\n"; # 可新增:打印响应头,检查Connection字段 # print map { "# $_: $h{$_}\n" } sort keys %h; my $buf; while (1) { my $n = $s->read_entity_body($tmp, 20); last unless $n; $buf .= $tmp; } $buf =~ s/\r//g; print "Request $iter completed.\n"; }
错误输出
Docker环境下执行脚本的错误结果:
Reading response for request 1. # -------------------- # 200 OK Request 1 completed. Reading response for request 2. read timeout at /usr/local/lib/perl5/site_perl/5.32.1/Net/HTTP/Methods.pm line 274.
排查与修复建议
- 核对版本差异:在Docker环境中执行
perl -MNet::HTTP -e 'print $Net::HTTP::VERSION',查看当前版本与桌面环境的6.22是否一致。版本差异是此类问题的常见根源。 - 检查服务器连接响应头:在测试脚本中添加代码打印所有响应头,重点查看
Connection字段是否为Keep-Alive。如果服务器返回Connection: close,则长连接会被主动关闭,第二次请求自然超时。 - 排查Docker网络环境:在容器内用curl测试长连接是否正常:
curl -v --keepalive-time 5 https://www.neverssl.com/ https://www.neverssl.com/,验证是否是容器网络(如NAT、防火墙、代理)导致长连接被中间设备断开。 - 对比Net::HTTP代码逻辑:查看Docker环境中
Net/HTTP/Methods.pm第274行的代码,对比桌面版本的对应逻辑,确认是否存在版本间的长连接处理bug。 - 调整Net::HTTP版本:尝试在Docker环境中安装与桌面一致的Net::HTTP 6.22版本:
cpanm install Net::HTTP@6.22,或升级到最新稳定版本,验证问题是否消失。 - 检查Perl版本的socket差异:Perl 5.32.1与5.30.2在IO::Socket的默认配置上可能存在差异,可在测试脚本中打印socket的TCP keepalive属性:
print "SO_KEEPALIVE: ", $s->sockopt('SO_KEEPALIVE'), "\n";,确认是否开启了TCP层面的长连接保活机制。 - 修复脚本笔误:测试脚本中
write_request方法的参数里多了一个逗号,虽然不影响当前执行,但建议修正为GET => "/", 'User-Agent' => ...,避免潜在的语法问题。
内容的提问来源于stack exchange,提问作者BlueMonkMN
相关产品推荐
相关产品推荐

