Matlab: TCP-соединение Fread data Размер Предупреждение Ошибка - PullRequest
0 голосов
/ 04 ноября 2018

У меня есть TCP-сервер в моем коде Matlab, мой клиент отправляет некоторые данные (максимум 4 байта) по некоторым триггерам из другого приложения в Matlab. Я получаю эти номера, но я также получаю это предупреждающее сообщение много раз:

Предупреждение. Указанный объем данных не был возвращен в течение периода ожидания. «tcpip» не может прочитать все запрошенные данные. Для получения дополнительной информации о возможных причинах см. Предупреждения о прочтении протокола TCPIP.

clc;
t = tcpip('0.0.0.0', 55000,'InputBufferSize', 1024,'NetworkRole','Server', 'TimeOut', 0.5);
fopen(t);
while(1)    
    data = fread(t, 4, 'char');    
    dataChar = char(data);
    dataDouble = str2double(dataChar);  
      if (~isnan(dataDouble))
          if (dataDouble == 0)
              fclose(t); % closing the tcp connecting
              error('0 value is received!') % to jump out of Matlab run mode
          else
              disp("Last Receieved double was: " + dataDouble)
          end       
      end       
  end

Я также пытался получить (obj1, 'BytesAvailable'), но он выдает ошибку. Кто-нибудь знает, как обойти это предупреждение?

1 Ответ

0 голосов
/ 05 ноября 2018

Вы пытаетесь прочитать данные из объекта tcpip, пока они не должны быть прочитаны (т. Е. Буфер уже пуст). Matlab будет ждать некоторое время, чтобы увидеть, что произойдет, а затем выдаст предупреждение. Обычный способ работы с tcpip obj - выполнить обратный вызов для определенного события и использовать этот обратный вызов для чтения данных из буфера.

Существует два режима: либо запуск буфера, когда найден определенный терминатор (например, перевод строки, если читается текст), либо когда получено определенное количество байтов.

Предполагая, что все сообщения имеют длину 4 байта, синтаксис будет:

t = tcpip('0.0.0.0', 55000,'InputBufferSize', 1024,'NetworkRole','Server', 'TimeOut', 0.5);
t.BytesAvailableFcnCount = 4;     % n=4
t.BytesAvailableFcnMode = 'byte'; %Read after n bytes have been received
t.BytesAvailableFcn     = @myTcpipCallback;
fopen(t);

Обратный вызов будет вызываться каждый раз, когда получено 4 байта. Синтаксис функции обратного вызова:

function myTcpipCallback(obj,evt)
    data=fread(obj,4,'char'); %Read 4 characters
    % ... do something with data ... %
    if bad_data_received==true
         fclose(obj);
    end
end

Цикл while не является необходимым, он уже обрабатывается внутри объекта tcpip. Синтаксис функции обратного вызова соответствует стандарту Matlab callbackFunction(obj,evt), где obj - это объект, откуда происходит событие, инициирующее обратный вызов (здесь объект tcpip, но графические объекты работают одинаково), а evt структура, содержащая данные о событие (например, IP / порт, откуда приходит сообщение; для события KeyPress, которое будет ключом и модификаторами).

Вы пишете, что клиенту из другого приложения будет отправлено максимум 4 байта. Действительно удобнее иметь фиксированное количество байтов (это может быть достигнуто путем заполнения сообщений на стороне клиента), или какой-либо терминатор должен отмечать конец, если происходит массаж.

При работе с терминатором (если, например, каждое сообщение заканчивается переводом строки), синтаксис будет следующим:

t.BytesAvailableFcnMode = 'terminator';
t.Terminator = char(10);     % or newline or recent versions of Matlab

и обратный вызов

function myTcpipCallback(obj,evt)
    data=[obj.UserData ; fread(obj,obj.BytesAvailable,'char')]; %Read all available characters
    %Just in case, check that we have not received more than one message
    term=[0;find(data==obj.Terminator)];
    for ii=1:length(term)-1
       msg=data(term(ii)+1:term(ii+1));
       %Do something with msg%
    end
    obj.UserData=data(term(ii)+1:end);
end

Если клиент отправляет данные быстро, некоторые дополнительные данные могли быть буферизованы, пока функция обратного вызова ожидала в очереди, поэтому к моменту ее выполнения может быть доступно несколько сообщений. Код должен учитывать эту возможность. К сожалению, количество байтов, доступных в буфере при запуске обратного вызова, отсутствует в данных события.

Наконец, если вы намереваетесь получать сообщения произвольной длины со сложными правилами, чтобы определить, завершен он или нет, другой возможностью является чтение байтов один за другим и где-нибудь иметь свой собственный буфер, например, в объекте userdata.

t.BytesAvailableFcnCount = 1;     % n=1
t.BytesAvailableFcnMode = 'byte'; %Read after n bytes have been received

и обратный вызов:

function myTcpipCallback(obj,evt)
    % Bufferize
    obj.UserData=[obj.UserData ; fread(obj,1,'char')]; %Read 1 byte

    % Check if the message if known
    msg = obj.UserData;
    if isComplete(msg)  % 
         obj.UserData=[]; % empty buffer
         processMessage(msg); % do something with message
    end
end
...