使用 Java 在服务器应用程序和 Matlab 客户端之间进行套接字通信
我有一个编写的 C++ 服务器应用程序,我希望能够从 Matlab 控制它。到目前为止,我已经使用 mex 函数进行套接字通信,但我想放弃 mex 函数并直接在 m 文件中使用内联 Java。这将是一个更加简化的解决方案。
我的基于 C++ 的独立应用程序需要一条消息,其中包含按以下顺序排列的数据。 。 。
协议的这一部分是固定的,无法更改:
uint32 magic_number - 这是一个幻数 (445566),必须位于 消息的开头或消息的其余部分将被忽略。
uint32 num_bytes - 这是消息块其余部分使用的字节数 (不包括这最初的 8 个字节)
这部分协议是我设计的,可以更改:
接下来是由 4 个 uint8 值组成的标头(如 ipv4 地址) 向应用程序发送以下数据代表的信息(如果有任何数据)
在此之后,剩余的字节可以代表许多不同的事物。 最常见的是一个字符串(键值),后跟一长浮点值数组(音频数据)。但是,可能只是一个字符串,或者它们可能只是一个浮点值数组。 4 个 uint8 值让服务器知道这里会发生什么。
正如你所看到的,我目前正在将所有内容压缩到一个 uint8 数组中(一个巨大的组合)。这是因为 java“write”函数需要一个字节数组,而 Matlab uint8 数组是兼容的数据类型,正如我在使用 Mathworks 网站 将数据传递给 Java 方法
我不是 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 中做到这一点?我最终也想使通信成为双向的,但这可以等等。感谢您的阅读。
I have a written C++ server app that I would like to be able to control from 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. This will be a more streamlined solution.
My C++ based standalone app expects a message with the following data in the following order . . .
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 num_bytes -
this is the number of bytes used for the rest of the message block
(excluding this initial 8 bytes)
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)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.
As you can see, I am currently squeezing everything into an array of uint8 (a colossal 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
I'm not a Java programmer, but I have managed to get a very simple bit of communication code up and running this afternoon. 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. In C/C++ it is very easy to append different data types in a contiguous block of memory and then send it. Is there a simple way for me to do this here in Java? I would eventually like to make the communications 2-way also, but this can wait for now. Thanks for reading.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这里至少有两个单独的问题。一是如何构建使用这样的协议的 Matlab 代码。另一个是如何在您拥有的有线协议中表示可能复杂的数据。
至于组织 Matlab 代码,您可以使用类以更结构化的方式组织消息,并使用
typecast
将数字转换为字节。也许是这样的。这假设您的客户端和服务器具有相同的原始类型的本机表示,并忽略网络字节排序(htonl/ntohl)。我认为更具可读性,并且代码味道更少。作为调用者,您可以以更结构化的形式处理数据,并且它将到类的编组方法内的线协议字节的转换封装起来。 “convertPayload”就是“将由许多不同数据类型组成的通用内存块缝合在一起”。在 Matlab 中,
uint8
数组是一种将不同数据类型的表示形式附加到连续内存块中的方法。它基本上是一个unsigned char []
的包装器,具有自动重新分配功能。typecast(...,'uint8')
相当于在 C/C++ 中对char *
进行重新解释转换。查看他们两个的帮助。但这带来了更多问题。服务器如何知道有效负载的每个组件的长度、它们的形状(如果是多维的)以及它们各自的类型是什么?或者如果它们是复杂的数据类型怎么办——它们可以嵌套吗?您可能需要在每个有效负载元素中嵌入小标头。上面的代码假设 4 字节有效负载类型标头完整地描述了有效负载内容。
听起来您正在寻找的可能是一种基于异构数组的数据的自描述格式。已有可用的格式,包括 NetCDF、HDF5 和 Matlab 自己的 MAT 文件。 Matlab 内置了对它们的支持,或者您可以为它们引入第三方 Java 库。
就速度而言——每次跨越 Matlab/Java 边界传递数据时,您都必须付费。大型原始数组的转换成本相对较低,因此您可能希望在将消息传递给 Java 之前将大部分消息打包到 Matlab 中的字节数组中,而不是进行大量单独的 write() 调用。实际上,这取决于您的数据有多大和复杂程度。请参阅 MATLAB OOP 速度慢还是我做错了什么吗? 粗略了解一些 Matlab 操作(包括 Java 调用)的成本。 (全面披露:这是一个自插头。)
There's at least two separate issues here. One is how to structure Matlab code that speaks a protocol like this. 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. 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).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". In Matlab, a
uint8
array is a way to append representations of different data types together in a continguous block of memory. It's basically a wrapper around anunsigned char []
, with automatic reallocation. Andtypecast(...,'uint8')
is sort of the equivalent of doing a reinterpret cast tochar *
in C/C++. 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.
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. Matlab has built-in support for them, or you could pull in third-party Java libraries for them.
As far as speed - You're going to have to pay each time you pass data across the Matlab/Java boundary. 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. It'll depend in practice on how big and complex your data is. See Is MATLAB OOP slow or am I doing something wrong? for a rough idea of the cost of some Matlab operations, including Java calls. (Full disclosure: that's a self-plug.)