You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Perl脚本sysread()读取ADAM模块时无限阻塞的排查与解决

研华ADAM-6000/6200模块Perl通信脚本sysread阻塞问题排查求助

我用Perl编写了与研华ADAM-6000/6200系列以太网IO模块通信的脚本,通过Socket循环读取数据。此前运行正常,但现在脚本会卡在sysread()处无限阻塞;重启脚本后可短暂恢复,随后又会卡在相同位置。以下是相关代码、执行输出及strace日志,求排查与解决方法:

代码片段

socket($socket, PF_INET, SOCK_STREAM, getprotobyname('tcp')) or die "Unable to Connect";
connect($socket, sockaddr_in('1000', inet_aton($ip_address))

....

print "\n\ndo_command() begin:\n";
print "Send: " . Data::Dumper::qquote($str) . "\n";

syswrite($socket, $str);
usleep(600000);
print "Wrote to socket\n";
print "Waiting on sysread to finish...\n";

my $bytes = sysread($socket, $data_line, 200);

print "Data Read: " . Data::Dumper::qquote($data_line) . "\n";
print "Bytes Read: $bytes\n";

执行输出

do_command() begin:
Send: "#01\r"
Wrote to socket
Waiting on sysread to finish...

strace日志

write(4, "#01\r", 4)                    = 4
clock_nanosleep(CLOCK_REALTIME, 0, {tv_sec=0, tv_nsec=600000000}, NULL) = 0
write(1, "Wrote to socket\n", 16)       = 16
write(1, "Waiting on sysread to finish...\n", 32) = 32
read(4, ">+00.018+00.016+00.020+00.008-00"..., 200) = 58
write(1, "Data Read: \"\>+00.018+00.016+00.0"..., 73) = 73
write(1, "Bytes Read: 58\n", 15)        = 15
write(1, "\n", 1)                       = 1
write(1, "Sleeping for .1 seconds\n", 24) = 24
clock_nanosleep(CLOCK_REALTIME, 0, {tv_sec=0, tv_nsec=100000000}, NULL) = 0
write(1, "Read Cycle\n", 11)            = 11
write(1, "\n\ndo_command() begin:\n", 22) = 22
write(1, "Send: \"#01\\r\"\n", 14)      = 14
write(4, "#01\r", 4)                    = 4
clock_nanosleep(CLOCK_REALTIME, 0, {tv_sec=0, tv_nsec=600000000}, NULL) = 0
write(1, "Wrote to socket\n", 16)       = 16
write(1, "Waiting on sysread to finish...\n", 32) = 32
read(4,

排查与解决建议

  • 替换固定延时为Socket超时设置:不要依赖usleep的固定等待,给Socket设置读写超时。可以改用IO::Socket::INET创建连接(支持Timeout参数),或者用setsockopt设置SO_RCVTIMEO和SO_SNDTIMEO,避免sysread无限阻塞。
  • 检查模块连接状态:若sysread返回0,说明模块已断开连接,需重新建立Socket。同时查看模块的状态页面或日志,确认是否存在连接数限制、缓存溢出等问题。
  • 优化响应完整性校验:ADAM模块的响应有固定格式(如以>开头),不要固定读取200字节,应循环读取直到收到完整响应(比如读到特定结束标记),同时配合超时机制。
  • 抓包排查网络问题:用tcpdump或Wireshark抓包,确认发送#01\r后模块是否返回响应。若模块未发送,排查模块或网络链路;若模块已发送但脚本未收到,检查是否有丢包、防火墙拦截等情况。
  • 用select做可读检查:在调用sysread前,用select检查Socket是否有可读数据并设置超时,避免直接阻塞。示例代码:
    my $rin = '';
    vec($rin, fileno($socket), 1) = 1;
    # 等待5秒,检查是否有可读数据
    my $nfound = select($rin, undef, undef, 5);
    if ($nfound > 0) {
        my $bytes = sysread($socket, $data_line, 200);
        # 处理读取到的数据
    } else {
        # 超时处理:关闭旧连接,重新建立连接
        close($socket);
        # 重新执行socket创建和连接逻辑
    }
    

内容的提问来源于stack exchange,提问作者Dennis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 02:57:49