服务器应用程序和使用Java的Matlab客户端之间的套接字通信

时间:2012-01-25 17:59:19

标签: java c++ sockets matlab interprocess

我有一个编写的C ++服务器应用程序,我希望能够从Matlab控制。到目前为止,我已经使用mex函数进行套接字通信,但我想抛弃mex函数并直接在m文件中使用内联Java。这将是一个更简化的解决方案。

基于My C ++的独立应用程序需要按以下顺序显示包含以下数据的消息。 。

该协议的这一部分是固定的,无法更改:

  • uint32 magic_number - 这是一个必须达到的幻数(445566) 消息的开头或消息的其余部分将被忽略。

  • uint32 num_bytes - 这是用于消息块其余部分的字节数 (不包括这个最初的8个字节)

这部分协议是由我设计的,可以更改:

  • 接下来是一个由4个uint8值组成的标题(如ipv4地址) 向应用程序发信号通知以下数据代表什么(如果有任何数据)

  • 在此之后,剩余的字节可以代表许多不同的东西。 最常见的是,这将是一个字符串(键值),后跟一长串浮点值(音频数据)。但是,可能只有一个字符串,或者它们可能只是一个浮点值数组。 4 uint8值让服务器知道这里会发生什么。

正如你所看到的,我现在正在把所有东西都挤进一堆uint8(巨大的kludge)。这是因为java“write”函数需要一个字节数组,而Matlab uint8数组是兼容的数据类型,就像我在Mathworks网站上使用下表时所发现的那样Passing Data to a Java Method

我不是Java程序员,但是我已经设法在今天下午获得了一段非常简单的通信代码。任何人都可以帮助我做得更好吗?

import java.net.Socket
import java.io.*

mySocket = Socket('localhost', 12345);
output_stream   = mySocket.getOutputStream;
d_output_stream = DataOutputStream(output_stream);


data = zeros(12,1,'uint8');

%Magic key: use this combination of uint8s to make
% a uint32 value of = 445566 -> massive code-smell
data(1) = 126;
data(2) = 204;
data(3) = 6;

%Size of message block:
%total number of bytes in following message including header
%This is another uint32 i.e. (data(5:8))

data(5) = 4;

%header B: a group of 4 uint8s
data(9) = 1;
data(10) = 2;
data(11) = 3;
data(12) = 4;

%Main block of floats
%????


d_output_stream.write(data,0,numel(data));


pause(0.2);
mySocket.close;

我已尝试发送一个由我想发送的数据的不同部分组成的java对象,但我不确定它们最终是如何在内存中排序的。在C / C ++中,很容易在连续的内存块中附加不同的数据类型然后发送它。有没有一种简单的方法让我在Java中这样做?我最终也希望双向进行通信,但现在可以等待了。谢谢你的阅读。

1 个答案:

答案 0 :(得分:1)

这里至少有两个不同的问题。一个是如何构建像这样的协议的Matlab代码。另一个是他如何在这个有线协议中表示可能的复杂数据。

就组织Matlab代码而言,您可以使用类以更结构化的方式组织消息,并使用typecast将数字转换为字节。也许这样的事情。这假设您的客户端和服务器具有相同的原始类型的本机表示,并忽略网络字节顺序(htonl / ntohl)。

classdef learnvst_message
    %//LEARNVST_MESSAGE Message for learnvst's example problem
    %
    % Examples:
    % msg = learnvst_message;
    % msg.payload = { 'Hello world', 1:100 }
    % msg.payloadType = uint8([ 5 12 0 0 ]);  % guessing on this

    properties
        magicNumber = uint32(445566);
        payloadType = zeros(4, 1, 'uint8');  %// header B
        payload = {};
    end

    methods
        function out = convertPayload(obj)
        %//CONVERTPAYLOAD Converts payload to a single array of bytes
        byteChunks = cellfun(@convertPayloadElement, obj.payload, 'UniformOutput',false);
        out = cat(2, byteChunks{:});
        end

        function out = marshall(obj)
        payloadBytes = convertPayload(obj);
        messageSize = uint32(4 + numel(payloadBytes)); %// ex first 8 bytes
        out.headerBytes = [
            typecast(obj.magicNumber, 'uint8') ...
            obj.payloadType ...
            typecast(messageSize, 'uint8')];
        out.payloadBytes = payloadBytes;
        end

        function sendTo(obj, host, port)
        m = marshall(obj);
        mySocket = Socket(host, port);
        d_output = mySocket.getOutputStream();
        d_output.write(m.headerBytes, 0, numel(m.headerBytes));
        d_output.write(m.messageBytes, 0, numel(m.messageBytes));
        mySocket.close();
        end

    end
end

function out = convertPayloadElement(x)
if isnumeric(x)
    out = typecast(x, 'uint8');
elseif ischar(x)
    % Assumes receiver likes 16-bit Unicode chars
    out = typecast(uint16(x), 'uint8');
else
    % ... fill in other types here ...
    % or define a payload_element class that marshalls itself and call
    % it polymorphically
    error('Unsupported payload element type: %s', class(x));
end
end

我认为更具可读性,而且代码味道更少。作为调用者,您可以使用更结构化的形式处理数据,并将转换封装到类的编组方法中的有线协议字节。 “convertPayload”就是“将由许多不同数据类型组成的通用内存块拼接在一起”。在Matlab中,uint8数组是一种在不连续的内存块中将不同数据类型的表示附加在一起的方法。它基本上是unsigned char []的包装器,具有自动重新分配功能。 typecast(...,'uint8')等同于在C / C ++中对char *进行重新解释。请参阅两者的帮助。

但这会带来更多问题。服务器如何知道有效载荷的每个组件有多长,多维时它们的形状是什么,以及它们各自的类型是什么?或者如果它们是复杂的数据类型 - 它们可以嵌套吗?您可能需要在每个有效内容元素中嵌入小标题。上面的代码假定4字节有效负载类型标头完全描述了有效负载内容。

听起来你正在寻找的可能是一种基于异构数组的数据的自描述格式。现有格式,包括NetCDF,HDF5和Matlab自己的MAT文件。 Matlab内置了对它们的支持,或者你可以为它们引入第三方Java库。

就速度而言 - 每次在Matlab / Java边界传递数据时都需要付费。大型原始数组的转换成本相对较低,因此您可能希望在将其传递给Java之前将大部分消息打包在Matlab中的字节数组中,而不是进行大量单独的write()调用。实际上,这取决于您的数据的大小和复杂程度。请参阅Is MATLAB OOP slow or am I doing something wrong?,了解一些Matlab操作(包括Java调用)的成本。 (完全披露:这是一个自我插件。)