通过带有消息(VLI)Ruby的套接字发送xml数据

时间:2013-12-13 13:59:11

标签: ruby-on-rails ruby xml sockets

Ruby新手。第一次发布任何通信协议不足的借口:)

这个网站提供了很大的帮助和“巨大的!!!”感谢所有人。

我需要将我的rails应用程序连接到电力供应商api,这样我就可以向我的网络客户提供电力。我需要一些帮助来简单地将初始请求发送到API

知识产权:41.204.194.188 港口:8945

第一个块:什么是消息变量长度指示符(VLI)?

“每个发送到/来自BizSwitch的消息前面有2个字节.2个字节称为可变长度指示符。字节1-2表示消息中的字节数(不包括前2个字节).2个字节表示网络字节顺序中的16位无符号整数。请注意,如果正在发送压缩消息,则必须首先压缩消息,以便在发送之前确定其长度。“

忽略压缩。

链接到api doc:https://dl.dropboxusercontent.com/u/3815995/Ipay-prepaidElecTransactionSpec.pdf

简单供应商请求示例:

<ipayMsg client="ipay" term="1" seqNum="0" time="2002-05-16 10:55:30 +0200"> 
<elecMsg ver="2.37">
<vendReq> 
<ref>136105500001</ref> 
<amt cur="ZAR">11400</amt> 
<numTokens>1</numTokens> 
<meter>A12C3456789</meter>
<payType>cash</payType>
</vendReq > 
</elecMsg>
</ipayMsg>

简单供应商响应示例

<ipayMsg client="ipay" term="1" seqNum="0" time="2002-05-16 10:55:35 +0200">
<elecMsg ver="2.37"
<vendRes> <ref>136105500001</ref>
<res code="elec000">OK</res>
<util addr="Megawatt Park, Contact Centre tel 086-003-7566" taxRef="4740101508" distId="6004708001509">Eskom Online</util>
<stdToken units="346.34" rctNum="12345678" amt="10000" tax="1400">12345678901234567890</stdToken>
<rtlrMsg>060000 Warning: This meter is not configured for FBE.</rtlrMsg>
<customerMsg>Meter not registered for Free Basic Electricity. Please apply at your local office.</customerMsg>
</vendRes>
</elecMsg>
</ipayMsg>

我已经走到这一步了,我似乎已经联系了,但我如何实际发送和接收回复?我已经尝试使用谷歌搜索帮助但尚未找到如何发送XML数据包然后收到响应。

#!/usr/bin/env ruby
require 'socket'

begin
 socket = TCPSocket.new('41.204.194.188', 8945)
rescue => e
 puts "error: #{e}"
else
 puts "connected"
end
socket.close

非常感谢任何帮助或在正确的方向上轻推。

亲切的问候,

杰米

2 个答案:

答案 0 :(得分:0)

太棒了,我明白了。与套接字通信的主要问题是发送消息变量长度指示符。这个stackoverflow问题让我在写入路径“Ruby - How to represent message length as 2 binary bytes

步骤1:确定我的xml消息长度= message.size

标头中的第一个字段必须是消息长度,它以网络字节顺序定义为2个二进制字节消息长度。

第2步:message_variable_length_indicator = [length] .pack(“n”)

第3步:连接套接字streamSock = TCPSocket :: new('41 .204.194.188',8945)

第4步:streamSock.write(message_variable_length_indicator)

第5步:streamSock.write(消息)

步骤6:获得响应str = streamSock.recvfrom(1000)

现在处理超时但至少我正在连接:)

答案 1 :(得分:0)

我在PHP中完成此操作可能会让你从下面的代码中得到它的工作正常我的请求。

function sendSocketRequest($XmlString, $Socket_Request) {
    if (!($sock = socket_create(AF_INET, SOCK_STREAM, 0))) {
        $errorcode = socket_last_error();
        $errormsg = socket_strerror($errorcode);
        die("Couldn't create socket: [$errorcode] $errormsg \n");
    }

    if (!socket_connect($sock, $Socket_Request['HostName'], $Socket_Request['Port'])) {
        $errorcode = socket_last_error();
        $errormsg = socket_strerror($errorcode);
        die("Could not connect: [$errorcode] $errormsg \n");
    }

    $status = socket_write($sock, pack_int32be(strlen($XmlString)), 4);
    $status = socket_write($sock, $XmlString, strlen($XmlString));
    $response = socket_read($sock, $this->_socketReadLength);

    socket_close($sock);
    return substr($response, 2);
}

function pack_int32be($i) {
    if ($i < -2147483648 || $i > 2147483647) {
        die("Out of bounds");
    }
    return pack('C4', ($i >> 24) & 0xFF, ($i >> 16) & 0xFF, ($i >> 8) & 0xFF, ($i >> 0) & 0xFF
    );
}
$socketResponse = sendSocketRequest($yourXMLString, array('HostName'=>'<HostName>','Port'=>'<Port>');