2011-02-14 100 views
3

我目前有一个问题与外部系统通信(对于那些知道它的红匣子)。 他们的系统依赖于发送和接收命令,这些命令是作为十六进制值构建的,随后是数据长度,然后是数据本身,这相当于一个长 - 短的任何内容。Perl IO :: Socket连续读取/写入

下面的代码演示了如何连接和登录,它在我接收到预期响应时成功完成。

我的问题是当我发送下一个命令时,我期望的响应是来自原始响应的尾随数据。任何人都可以引导我在正确的方向吗?

#!/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#[email protected]@......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 .>[email protected] 
    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 .;#"@[email protected] 
    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 

回答

2
  1. 你永远读超过4个字节的每个请求后,服务器。由于您没有阅读整个回复,因此无法对整个回复进行解码,并且您没有正确的位置来阅读下一个回复。

  2. 您使用"h*"包模板似乎是错的每一次你使用它 - 如果不出意外,应该是"h8"。特别是,unpack "h*sx" *不可能工作,并在这里发生错误。

  3. reverse的使用也是非常令人担忧的 - 为什么不使用正确排序的pack模板开始呢?

  4. 不要重复自己!编写函数来执行发送和接收操作,而不是为每一个命令重写相同的代码。

一些有用的代码一开始是:

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); 
} 

虽然这还没有某种理智的规范,为协议的所有投机性很强 - 包转储你似乎表现出不承担与你提供的代码非常相关。