2011-02-14 98 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); 
} 

雖然這還沒有某種理智的規範,爲協議的所有投機性很強 - 包轉儲你似乎表現出不承擔與你提供的代碼非常相關。