Socket communication between server application and Matlab client using Java

I have a written application on a C ++ server that I would like to receive from Matlab. So far, I have used the mex function to communicate sockets, but I would like to disable the mex function and use the built-in Java directly in m files. This will be a more streamlined solution.

The average standalone application in my C ++ is expecting messages with the following data in the following order.,.

This part of the protocol is fixed and cannot be changed:

  • uint32 magic_number is a magic number (445566) that should be at the beginning of the message or the rest of the message will be ignored.

  • uint32 num_bytes is the number of bytes used for the rest of the message block (excluding these initial 8 bytes)

This part of the protocol was developed by me and can be changed:

  • Next comes the header, consisting of 4 uint8 values ​​(for example, ipv4 address) alarm for the application that represent the following data (if any data follows)

  • After that, the remaining bytes can represent many different things. Most often it will be a string (key value) followed by a long array of floating point values ​​(audio data). However, it could just be a string, or it could just be an array of floating point values. The uint8 values ​​of 4 let the server know what to expect from here.

As you can see, I am currently compressing everything into a uint8 array (colossal kludge). This is because the java "write" function expects an array of bytes, and the Matlab uint8 array is a compatible data type that I found when using the following table on the Mathworks website Passing data to the Java method

I am not a Java programmer, but today I managed to get a very simple bit of communication code. Can someone 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 ie (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 experimented with sending a java object consisting of different pieces of data that I would like to send, but I'm not sure how they are ultimately ordered in memory. In C / C ++, it is very easy to add different types of data to a contiguous block of memory, and then send it. Is there an easy way to do this here in Java? In the end, I would also like to make a connection in two directions, but this can wait. Thanks for reading.

+4
source share
1 answer

There are at least two separate questions. One of them is how to structure the matlab code that talks about such a protocol. Another is how to represent possibly complex data in this wired protocol that you have.

Regarding the organization of Matlab code, you can use the class to organize the message in a more structured way and use typecast to convert numbers to bytes. Maybe something like this. This assumes that your client and server have the same native representation of primitive types and ignore the byte order on the network (htonl / ntohl).

 classdef learnvst_message %//LEARNVST_MESSAGE Message for learnvst 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 slightly less code smell. As a caller, you can work with data in a more structured form and encapsulate the conversion to bytes of the wire protocol inside the class sorting method. This "convertPayload" is what "stitches together a common block of memory together from many different data types." In Matlab, the uint8 array is a way to add representations of different data types together in a limited block of memory. This is basically a wrapper around unsigned char [] with automatic redistribution. And typecast(...,'uint8') is a kind of equivalent that reinterprets casts to char * in C / C ++. See Help for both of them.

But that raises more questions. How does the server know how long each component of the payload is, what is their shape, multidimensional, and what are their respective types? Or what if they are complex data types - could they nest? You may need to embed small headers inside each payload element. The code above assumes that the 4-byte header of the payload type fully describes the contents of the payload.

It looks like what you are looking for could be a kind of self-descriptive format for heterogeneous arrays. There are existing formats for this, including NetCDF, HDF5 and Matlab's own MAT files. Matlab has built-in support for them, or you can use third-party Java libraries for them.

As for speed, you have to pay every time you transfer data across the Matlab / Java border. Large primitive arrays are relatively cheap to convert, so you probably want to pack most of the message in a byte array in Matlab before passing it to Java, instead of making many separate write () calls. In practice, this will depend on how large and complex your data is. See Is MATLAB OOP Slower or Am I Something Wrong? for a rough idea of ​​the cost of some Matlab operations, including Java calls. (Full disclosure: this is self-locking.)

+1
source

Source: https://habr.com/ru/post/1393003/


All Articles