Socket communication between server applications and MATLAB clients using java
I have a written C server application that I hope can be controlled from MATLAB So far, I have used the mex function for socket communication, but I want to abandon the mex function and use inline Java directly in the m file This will be a simpler solution
My C-based stand-alone application needs to display messages containing the following data in the following order
This part of the agreement is fixed and cannot be changed:
> uint32 magic_ Number – this is a magic number that must be reached (445566). The beginning 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 the first 8 bytes)
This part of the agreement was designed by me and can be changed:
>Next, a header composed of four uint8 values (such as IPv4 address) signals the application what the following data represents (if any) > after that, the remaining bytes can represent many different things Most commonly, this will be a string (key value) followed by a long string of floating point values (audio data) However, there may be only one string, or they may be just an array of floating point values The uint8 value lets the server know what will happen here
As you can see, I'm currently compressing everything into a uint 8 array (huge kludge) This is because the Java "write" function requires a byte array, and the MATLAB uint8 array is a compatible data type, as I found when using the following table on the MathWorks website
I'm not a java programmer, but I've managed to get a very simple communication code this afternoon Can anyone help me do 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,numel(data)); pause(0.2); mySocket.close;
I've tried to send a Java object consisting of different parts of the data I want to send, but I'm not sure how they will eventually be sorted in memory In C / C + +, it is easy to attach different data types to consecutive memory blocks and send it Is there a simple way for me to do this in Java? I finally hope to communicate in both directions, but now I can wait Thank you for reading
Solution
There are at least two different problems here One is how to build matlab code for protocols like this The other is how he represents possible complex data in this wired protocol
In terms of organizing matlab code, you can use classes to organize messages in a more structured way and use type conversion to convert numbers to bytes Maybe such a thing This assumes that your client and server have the same native representation of the original type, ignoring the network byte order (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,'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,numel(m.headerBytes)); d_output.write(m.messageBytes,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
I think it's more readable and the code tastes less As a caller, you can process the data in a more structured form and encapsulate the transformation into wired protocol bytes in the marshalling method of the class "Convertpayload" is "splicing common memory blocks composed of many different data types together" In MATLAB, uint8 array is a method to attach the representations of different data types together in consecutive memory blocks It is basically an unsigned char [] wrapper with automatic redistribution function And type conversion (...,'uint8 ') is equivalent to reinterpretation of char * in C / C + + See the help for both
But this will bring more problems How does the server know how long each component of the payload is, what their shape is when multidimensional, and what their respective types are? Or if they are complex data types – can they be nested? You may need to embed subheadings in each valid content element The above code assumes that the 4 - byte payload type header fully describes the payload content
It sounds like what you are looking for may be a self describing format of data based on heterogeneous arrays Existing formats, including NetCDF, HDF5 and Matlab's own mat files MATLAB has built-in support for them, or you can introduce third-party Java libraries for them
In terms of speed – you have to pay every time you transfer data at the MATLAB / Java boundary The conversion cost of large raw arrays is relatively low, so you may want to package most messages in byte arrays in MATLAB instead of making a large number of separate write () calls before passing them to Java In fact, it depends on the size and complexity of your data For an overview of the costs of some matlab operations, including Java calls, see is matlab OOP slow or am I doing something wrong (full disclosure: This is a self plug-in.)