2012-01-25 1 views
4

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

Мое автономное приложение на C++ ожидает сообщения со следующими данными в следующем порядке. , ,

Эта часть протокола является фиксированным и не может быть изменен:

  • uint32 magic_number - это магическое число (445566), который должен быть в начала сообщения или отдых сообщения будут проигнорированы.

  • UInt32 число_байт - это число байт, используемых для остальной части блока сообщений (исключая этих начальные 8 байт)

Эта часть протокола был разработан мной и может быть изменена:

  • Далее идет заголовок, выполненный из 4-х значений uint8 (как адрес iPv4) сигнализации в приложение, что представляет следующие данные (если какие-либо данные следующим образом)

  • После этого оставшиеся байты могут представлять разные вещи. Чаще всего это будет строка (значение ключа), за которой следует длинный массив значений с плавающей запятой (аудиоданные). Однако может быть просто строка, или они могут быть просто массивом значений с плавающей запятой. Значения 4 uint8 позволяют серверу знать, чего ожидать отсюда.

Как вы можете видеть, я в настоящее время сжимаю все в массив uint8 (колоссальный kludge). Это связано с тем, что функция «write» java ожидает, что массив байтов и массив Matlab uint8 будут совместимым типом данных, как я нашел при использовании следующей таблицы на сайте Mathworks. Passing Data to a Java Method

Я не программист на 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

Когда я отправляю данные между Matlab и Java, я отправляю java-объекты с необходимыми свойствами. Возможно, вы могли бы попробовать это. –

+1

Можете ли вы сузить «много разных вещей»? Будут ли его компоненты всегда быть массивом примитивных чисел или чего-то еще, непосредственно представляемого как примитивный массив Matlab? И вам нужно вернуть данные с сервера? –

+0

Вы уверены, что «размер блока сообщений» - это один байт? Это ограничит вас 256-байтовыми сообщениями. Это протокол, который вы сами разработали? –

ответ

1

Здесь есть как минимум два отдельных вопроса. Один из них заключается в том, как структурировать 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(). На практике это будет зависеть от того, насколько велики и сложны ваши данные. См. Is MATLAB OOP slow or am I doing something wrong? для приблизительного представления о стоимости некоторых операций Matlab, включая вызовы Java. (Полное раскрытие: это самозапуск.)

+0

Ничего себе! Спасибо за такой проницательный ответ и благодарность за ваше время. Сейчас очень поздно ночью, поэтому я буду экспериментировать с ним утром, сравним его с моим текущим решением mex и опубликую результаты. Я обязательно прочитаю существующие форматы, которые вы упомянули. Еще раз спасибо! – learnvst

+1

Рад помочь; Я не очень часто использую этот низкоуровневый материал Matlab. (Что хорошо - один тип typecast() на миллион строк кода звучит правильно.) Не забудьте использовать 'profile', чтобы узнать, где тратится время.Удачи. –

+0

Erm, «низкоуровневый Matlab» звучит как оксюморон, да. Я сказал, что собираюсь спать, но я солгал и должен был сделать это. , при возникновении ошибки при использовании вашего примера кода Первый входной аргумент должен быть полным, некоммерческим числовым значением. Ошибка в ==> Janke> @ (x) typecast (x, 'uint8') в 20 byteChunks = cellfun (@ (x) typecast (x, 'uint8'), obj.payload); ... определенно не спать сейчас. Еще раз спасибо. – learnvst