我目前在与外部系统进行通信时遇到问题(对于那些知道它的人来说,redbox刻录机)。 他们的系统依赖于发送和接收命令,这些命令构建为十六进制值,后跟数据长度,然后是数据本身,这相当于长短 - 无论如何。
下面的代码说明了如何连接和登录,当我收到预期的响应时它会成功。
我的问题是当我发送下一个命令时,我期望的响应是来自原始响应的尾随数据。有人能指导我朝正确的方向发展吗?
#!/usr/bin/perl
use IO::Socket;
use strict;
$| = 1;
print "======================================================================\n";
my $login = "88000100";
my $username = ""; # total = 11
my $password = ""; # total = 12
print "Attempting to connect ... \n";
my $sock = IO::Socket::INET->new(
PeerAddr => '10.8.12.20',
PeerPort => 1401,
Proto => 'tcp');
die "Could not create socket: $!\n" unless $sock;
print "Connected\n";
####################################################################
#Login
my $packed_cmd = pack "h* s x Z11 Z12", scalar(reverse($login)), '23', $username, $password;
print "Transmitting : Login cmd\n";
$sock->send($packed_cmd) or die "didn't send anything";
my $data;
$sock->recv($data,4);
$data = unpack( 'h*sx', $data );
my $response = substr($data,0,8);
$response = reverse($response);
print "Response is : $response \n" if $data;
print "Received from Server : $data\n" if $data;
#####################################################################
#Status
sleep(5);
my $socketStatus = $sock->connected;
print "Socket Active\n" if $socketStatus;
print "===== Recorder Status =====\n";
my $status_cmd = "88000102";
#print scalar reverse $suppress_call_cmd;
my $packed_cmd = pack "h*sx", scalar(reverse($status_cmd)), '0';
print "Transmitting : Status cmd\n";
$sock->send($packed_cmd);
##########################
$data = undef;
$sock->recv($data,4);
$data = unpack( 'h*sxlllll', $data );
my $response = substr($data,0,8);
$response = reverse($response);
print "Response is : $response \n." if $data;
print "Received from Server : $data\n." if $data;
输出:
======================================================================
Attempting to connect ...
Connected
Transmitting : Login cmd
Response is : 98000100
Received from Server : 00100089
Socket Active
===== Recorder Status =====
Transmitting : Status cmd
Response is : 00010004
.Received from Server : 40001000
如果有帮助,这是tcpdump的片段
登录请求
0x0000: 0000 5e00 0101 000c 2964 dc15 0800 4500 ..^.....)d....E.
0x0010: 0052 2320 4000 4006 e5f4 0a08 116e 0a08 .R#.@.@......n..
0x0020: 0c14 89e0 0579 0777 2a24 3843 08ff 8018 .....y.w*$8C....
0x0030: 002e 31d6 0000 0101 080a 6734 093d 0000 ..1.......g4.=..
0x0040: 0000 0001 0088 1700 0061 646d 696e 0000 .........admin..
0x0050: 0000 0000 xxxx xxxx xxxx xxxx xxxx xxxx ....xxxxxxxxxxxx
登录respose
0x0000: 000c 2964 dc15 001b 3f49 8400 0800 4500 ..)d....?I....E.
0x0010: 003e 73dd 4000 7f06 564b 0a08 0c14 0a08 .>s.@...VK......
0x0020: 116e 0579 89e0 3843 08ff 0777 2a42 8018 .n.y..8C...w*B..
0x0030: ffe1 e76a 0000 0101 080a 00de e48f 6734 ...j..........g4
0x0040: 093d 0001 0098 0400 0100 0000
状态请求
0x0000: 0000 5e00 0101 000c 2964 dc15 0800 4500 ..^.....)d....E.
0x0010: 003b 2322 4000 4006 e609 0a08 116e 0a08 .;#"@.@......n..
0x0020: 0c14 89e0 0579 0777 2a42 3843 0909 8018 .....y.w*B8C....
0x0030: 002e 31bf 0000 0101 080a 6734 1dc6 00de ..1.......g4....
0x0040: e48f 0201 0088 0000 00
答案 0 :(得分:2)
每次请求后,您永远不会从服务器读取超过4个字节。由于您没有阅读整个回复,因此您无法解码整个回复,并且您无法正确阅读下一个回复。
每次使用"h*"
包模板时,您的使用似乎都是错误的 - 如果没有别的,它应该是"h8"
。特别是,unpack "h*sx"
*不可能正常工作并在此处出错。
使用reverse
也非常令人担忧 - 为什么不直接使用具有正确字节顺序的包模板呢?
不要重复自己!编写函数来执行发送和接收操作,而不是为每个命令重写相同的代码。
一些有用的代码的开头是:
sub send_packet {
my ($sock, $cmd, $data) = @_;
my $packed = pack "H8Sxa*", $cmd, length $data, $data;
$sock->send($packed) or die "$! sending command";
}
sub recv_packet {
my ($sock) = @_;
my ($header, $data);
$sock->recv($header, 9) or die "$! receiving header";
my ($type, $length) = unpack "H8S", $header;
$sock->recv($data, $length) or die "$! receiving data";
return ($type, $data);
}
尽管如果没有对协议的某些理智规范,这些都是高度推测的 - 您显示的数据包转储似乎与您提供的代码完全没有关系。