简体   繁体   English

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

[英]Socket communication between server app and Matlab client using Java

I have a written C++ server app that I would like to be able to control from Matlab. 我有一个书面的C ++服务器应用程序,我希望能够从Matlab控制。 I have used a mex function for socket communication so far, but I would like to ditch the mex function and use inline Java directly in the m files. 到目前为止,我已经使用mex函数进行套接字通信,但我想抛弃mex函数并直接在m文件中使用内联Java。 This will be a more streamlined solution. 这将是一个更简化的解决方案。

My C++ based standalone app expects a message with the following data in the following order . 我的基于C ++的独立应用程序需要按以下顺序显示包含以下数据的消息。 . .

This part of the protocol is fixed and cannot be changed: 协议的这一部分是固定的,不能更改:

  • uint32 magic_number - this is a magic number (445566) that must be at the start of the message or the rest of the message will be ignored. uint32 magic_number - 这是一个必须位于消息开头的幻数(445566),否则将忽略消息的其余部分。

  • uint32 num_bytes - this is the number of bytes used for the rest of the message block (excluding this initial 8 bytes) uint32 num_bytes - 这是用于其余消息块的字节数(不包括此初始8字节)

This part of the protocol was designed by me and can be changed: 协议的这一部分是由我设计的,可以更改:

  • Next comes a header made of 4 uint8 values (like an ipv4 address) signalling to the app what the following data represents (if any data follows) 接下来是由4个uint8值(如ipv4地址)组成的标头,向应用程序发出以下数据表示的内容(如果有任何数据)

  • After this, the remaining bytes can represent many different things. 在此之后,剩余的字节可以代表许多不同的东西。 Most commonly this would be a string (key value) followed by a long array of floating point values (audio data). 最常见的是,这将是一个字符串(键值),后跟一长串浮点值(音频数据)。 However, there may just be a string, or they may just be an array of floating point values. 但是,可能只有一个字符串,或者它们可能只是一个浮点值数组。 The 4 uint8 values let the server know what to expect here. 4 uint8值让服务器知道这里会发生什么。

As you can see, I am currently squeezing everything into an array of uint8 (a colossal kludge). 正如你所看到的,我目前正在将所有东西压缩成uint8阵列(巨大的kludge)。 This is because the java "write" function expects a byte array and a Matlab uint8 array is a compatible data type as I found when using the following table on the Mathworks site Passing Data to a Java Method 这是因为java“write”函数需要一个字节数组,而Matlab uint8数组是兼容的数据类型,就像我在Mathworks站点上使用下表将数据传递给Java方法时所发现的那样

I'm not a Java programmer, but I have managed to get a very simple bit of communication code up and running this afternoon. 我不是Java程序员,但是我已经设法在今天下午获得了一个非常简单的通信代码。 Can anyone help me make this better? 任何人都可以帮助我做得更好吗?

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;

I have experimented with sending a java object composed of the different parts of the data that I would like to send, but I am not sure how they end up ordered in memory. 我已经尝试发送一个由我想发送的数据的不同部分组成的java对象,但我不确定它们最终是如何在内存中排序的。 In C/C++ it is very easy to append different data types in a contiguous block of memory and then send it. 在C / C ++中,很容易在连续的内存块中附加不同的数据类型然后发送它。 Is there a simple way for me to do this here in Java? 有没有一种简单的方法让我在Java中这样做? I would eventually like to make the communications 2-way also, but this can wait for now. 我最终也希望双向进行通信,但现在可以等待了。 Thanks for reading. 谢谢阅读。

There's at least two separate issues here. 这里至少有两个不同的问题。 One is how to structure Matlab code that speaks a protocol like this. 一个是如何构建像这样的协议的Matlab代码。 The other his how to represent possibly complex data in this wire protocol you have. 另一个是他如何在这个有线协议中表示可能的复杂数据。

As far as organizing the Matlab code, you could use a class to organize the message in a more structured manner, and use typecast to convert the numbers down to bytes. 就组织Matlab代码而言,您可以使用类以更结构化的方式组织消息,并使用typecast转换将数字转换为字节。 Maybe something like this. 也许这样的事情。 This assumes your client and server have the same native representation of primitive types, and ignores network byte ordering (htonl/ntohl). 这假设您的客户端和服务器具有相同的原始类型的本机表示,并忽略网络字节顺序(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

More readable, I think, and a bit less code smell. 我认为更具可读性,而且代码味道更少。 As a caller, you can work with the data in a more structured form, and it encapsulates the conversion to the wire-protocol bytes inside the class's marshalling method. 作为调用者,您可以使用更结构化的形式处理数据,并将转换封装到类的编组方法中的有线协议字节。 That "convertPayload" is what "stitches together a generic block of memory together made of many different data types". “convertPayload”就是“将由许多不同数据类型组成的通用内存块拼接在一起”。 In Matlab, a uint8 array is a way to append representations of different data types together in a continguous block of memory. 在Matlab中, uint8数组是一种在连续的内存块中将不同数据类型的表示附加在一起的方法。 It's basically a wrapper around an unsigned char [] , with automatic reallocation. 它基本上是一个unsigned char []的包装器,具有自动重新分配功能。 And typecast(...,'uint8') is sort of the equivalent of doing a reinterpret cast to char * in C/C++. 并且typecast(...,'uint8')相当于在C / C ++中对char *进行重新解释转换。 See the help for both of them. 请参阅两者的帮助。

But this brings up more questions. 但这会带来更多问题。 How does the server know how long each of the components of the payload are, what their shape is if multidimensional, and what their respective types are? 服务器如何知道有效载荷的每个组件有多长,多维时它们的形状是什么,以及它们各自的类型是什么? Or what if they're complex data types - could they nest? 或者如果它们是复杂的数据类型 - 它们可以嵌套吗? You might need to embed little headers inside each of the payload elements. 您可能需要在每个有效内容元素中嵌入小标题。 The code above assumes the 4-byte payload type header fully describes the payload contents. 上面的代码假定4字节有效负载类型标头完全描述了有效负载内容。

Sounds like what you're looking for may be a sort of self-describing format for heterogeneous array based data. 听起来你正在寻找的可能是一种基于异构数组的数据的自描述格式。 There are existing formats for that, including NetCDF, HDF5, and Matlab's own MAT files. 现有格式,包括NetCDF,HDF5和Matlab自己的MAT文件。 Matlab has built-in support for them, or you could pull in third-party Java libraries for them. Matlab内置了对它们的支持,或者你可以为它们引入第三方Java库。

As far as speed - You're going to have to pay each time you pass data across the Matlab/Java boundary. 就速度而言 - 每次在Matlab / Java边界传递数据时都需要付费。 Large primitive arrays are relatively cheap to convert, so you probably want to pack most of the message up in a byte array in Matlab before passing it to Java, instead of making lots of separate write() calls. 大型原始数组的转换成本相对较低,因此您可能希望在将其传递给Java之前将大部分消息打包在Matlab中的字节数组中,而不是进行大量单独的write()调用。 It'll depend in practice on how big and complex your data is. 实际上,这取决于您的数据的大小和复杂程度。 See Is MATLAB OOP slow or am I doing something wrong? 请参阅MATLAB OOP缓慢或我做错了什么? for a rough idea of the cost of some Matlab operations, including Java calls. 粗略了解一些Matlab操作的成本,包括Java调用。 (Full disclosure: that's a self-plug.) (完全披露:这是一个自我插件。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM