Связь через сокет между серверным приложением и клиентом Matlab с использованием Java - PullRequest
4 голосов
/ 25 января 2012

У меня есть написанное C ++ серверное приложение, которым я бы хотел управлять из Matlab.До сих пор я использовал функцию mex для связи через сокеты, но я хотел бы отказаться от функции mex и использовать встроенную Java непосредственно в m файлах.Это будет более рациональное решение.

Моё автономное приложение на 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?В конце концов, я хотел бы сделать связь также двухсторонней, но сейчас это может подождать.Спасибо за чтение.

1 Ответ

1 голос
/ 26 января 2012

Здесь есть как минимум две отдельные проблемы.Один из них заключается в том, как структурировать код 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') является своего рода эквивалентом повторного толкования в char * в C / C ++.См. Справку для них обоих.

Но это вызывает больше вопросов.Как сервер знает, как долго каждый из компонентов полезной нагрузки, какова их форма, если он многомерен, и каковы их соответствующие типы?Или что, если они являются сложными типами данных - могут ли они быть вложенными?Вам может понадобиться встроить маленькие заголовки в каждый из элементов полезной нагрузки.В приведенном выше коде предполагается, что 4-байтовый заголовок типа полезной нагрузки полностью описывает содержимое полезной нагрузки.

Звучит так, как будто вы ищете, может быть своего рода форматом самоописания для данных на основе гетерогенного массива.Для этого существуют форматы, в том числе NetCDF, HDF5 и собственные MAT-файлы Matlab.Matlab имеет встроенную поддержку для них, или вы можете использовать сторонние библиотеки Java для них.

Что касается скорости - вам придется платить каждый раз, когда вы передаете данные через Matlab /Java граница.Большие примитивные массивы относительно дешевы для преобразования, поэтому вы, вероятно, захотите упаковать большую часть сообщения в байтовый массив в Matlab перед передачей его в Java, вместо того чтобы выполнять множество отдельных вызовов write ().На практике это будет зависеть от того, насколько большими и сложными будут ваши данные.См. Медленно ли работает MATLAB OOP или я что-то не так делаю? , чтобы получить приблизительное представление о стоимости некоторых операций Matlab, включая вызовы Java.(Полное раскрытие: это саморазъем.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...