Перейти к содержанию
Fire Monkey от А до Я
  • 0

SendCommandWithResponse


Wovan2

Вопрос

Здравствуйте.

Пытаюсь через Tethering получить данные с удаленного приложения. Но все реализовано через события, и при наличии нескольких клиентов у меня возникла путаница, какому клиенту, что вернуть.

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

Похожих событий на принимающей стороне  не нашел. Ведь вызвать функцию на клиенте - пол дела. Надо чтобы сервер обработал запрос и вернул результат. Или что-то не понимаю.

Может кто может хотя бы намекнуть в какую сторону искать.

Ссылка на комментарий

Рекомендуемые сообщения

  • 0
1 час назад, Wovan2 сказал:

Не могу найти ни одного примера использования.

Там искать нечего. В глубине тетеринга эта команда - всего лишь совокупность

SendCommand(AConnection, ACommand);
Result := ReceiveCommand(AConnection);

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

Единственное что - следует самому создавать TTetheringCommand со своими параметрами, а не пользоваться готовыми SendStream и SendString

Изменено пользователем kami
Ссылка на комментарий
  • 0

Может, кто владеет этой технологией, подскажет как реализовать выполнение  функции на стороне сервера с возвратом результата клиенту без этого SendCommand, Другие клиенты не должны видеть друг друга и не должны перехватывать чужие данные.

Ссылка на комментарий
  • 0
26 минут назад, krapotkin сказал:

про тетеринг есть хорошее видео на ЮТ эмбаркадеро раша от Совцова

Смотрел уже. Ничего нового. Все то же, что и во всем инете. Шаблонные задачи во всех источниках одинаковые: подключились, послали, в событии получили.

Ссылка на комментарий
  • 0
29 минут назад, kami сказал:

Там искать нечего. В глубине тетеринга эта команда - всего лишь совокупность


SendCommand(AConnection, ACommand);
Result := ReceiveCommand(AConnection);

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

Единственное что - следует самому создавать TTetheringCommand со своими параметрами, а не пользоваться готовыми SendStream и SendString

Не могу сообразить как обрабатывать на сервере эти команды. При вызове функции SendCommandWithResponse на клиенте, на сервере срабатывают события BeforeSendData, AfterReceiveData, BeforeSendData, AfterReceiveData, BeforeSendData, AfterReceiveData. Именно так: 3 раза парами. Параметр ADataBuffer: TByteDynArray в каждом из этих вызовов разный. Видимо в этом TByteDynArray и прячется исходная структура TTetheringCommand? Как их преобразовывать друг в друга?

Где-то надо разобрать то, что послал клиент (как-то получить посланную структуру TTetheringCommand), потом, после нужной обработки создать такую же структуру ответа и куда-то уже ее засунуть. Не могу понять где, что и куда совать.

Ссылка на комментарий
  • 0
В 03.11.2017 в 17:34, kami сказал:

TTetheringCommand - есть метод Create, принимающий TBytes

А вот почему 3 пары событий - это не знаю...

В событиях AfterReceiveData, BeforeSendData параметр имеет тип TByteDynArray. Как его в тип TBytes перевести? Туплю. Только из Delphi 7 вылез.

Ссылка на комментарий
  • 0

На клиенте выполняю следующий код:

    LS := TStringList.Create;
    LS.Add('Привет - это я!');
    ACommand := TTetheringCommand.Create('MyCommand', 33, ['par1','par2'], LS);

    ed1.Text := 'Начало';
    try
    Resp := TAPClient.SendCommandWithResponse(TMClient.RemoteProfiles[0], ACommand);
    except
    on e:Exception do
     ShowMessage(e.Message)
    end;
    ed1.Text := 'Конец'

При выполнении всегда срабатывает исключение "Operation aborted".

На сервере в обработке TAPServerAfterReceiveData

memConnectedInfo.Lines.Add('TAPServerAfterReceiveData');
 tc := TTetheringCommand.Create(TBytes(ADataBuffer));
 try
 memConnectedInfo.Lines.Add(tc.Command);
 finally

 end;

Из нескольких срабатываниях выводится идентификатор Клиента. Хотя в Command вставляю 'MyCommand'.

Ни одного примера в во всем инете не нашел.

В 03.11.2017 в 19:12, wamaco сказал:

Эту статью тоже штудировал. Мало чем отличается по содержанию от всех остальных. Разве немного подробнее. Но TTetheringCommand нет и там.

Ссылка на комментарий
  • 0

Порядок событий на сервере


TAPServerBeforeSendData
wrWc0I8ol7
TAPServerAfterReceiveData
[пустая строка]
TAPServerBeforeSendData
{7FCD2085-28F1-4B42-9446-A73A0BC2873F}
TAPServerAfterReceiveData
{38BAA5D2-B0C3-E711-8018-AF8831B0713E}
TAPServerBeforeSendData
Error
TAPServerAfterReceiveData
[пустая строка]
TAPServerAfterReceiveData
[пустая строка]

После имени события выводится свойство TTetheringCommand.Command (как в коде выше)

Визуально похоже на обмен пакетами при сетевом общении

Сперва хеш пароля, потом обмен адресами, потом передача произвольных данных (в моем случае пустые объекты)

Ни у кого никаких мыслей не возникает? Мне бы понять в каком месте на сервере можно заполнить структуру ответа.

Попытка покопаться в исходных кодах ни к чему не привела. Есть интересная процедура DoOnIncomingData, но по какому событию она запускается  я не понял. Соответственно никакого события OnIncomingData у объекта TTetheringAppProfile нет.

Ссылка на комментарий
  • 0

К Indy у меня плохое отношение. Глючные, тормозные и громоздкие компоненты. На D7 пользуюсь Synapse, не в пример проще и предсказумее. Да, я знаю, Tethering реализован на Indy (возможно с этим и связано непостоянство установки соединения). Но в данном случае хотелось попробовать саму технологию, которая везде расписана как панацея от всех сетевых проблем. А оказывается не все так просто. Только что обнаружил, что метод Connect у меня не соединяет профили (выяснил это при скурпулезной отладке на Android). Хотя в примерах Delphi все работает нормально. Буду искать где накосячил. Возможно и код приведенный выше может оказаться рабочим.

Добавлено 12:11
Товарищи. Это пипец какой-то. Если на сервере задействую события TAPServerBeforeSendData или TAPServerAfterReceiveData, клиент перестает подключаться к профилю сервера. Без этих событий все нормально подключается.

Изменено пользователем Wovan2
Ссылка на комментарий
  • 0

Кое-что прояснилось при ближайшем рассмотрении. События TAPServerBeforeSendData иTAPServerAfterReceiveData по сути функции. И результат этих функций нужно обязательно переопределять Result := ADataBuffer. При этом, видимо, можно что-то поправить в команде, принимаемой или отсылаемой. Событие TAPServerAfterReceiveData на сервере срабатывает периодически, возможно по какому-то таймауту, с пустой командой.

Кстати среди всех этих событий мне удалось выловить и свою отправленную с клиента команду 'MyCommand'. Осталось обработать ее персонально.:)

Изменено пользователем Wovan2
Ссылка на комментарий
  • 0

И снова здравствуйте. Хотя и разговариваю сам с собой, но все же, может кто еще и откликнется.

В общем продолжаю мучить Tethering. В событии TAPServerAfterReceiveData удалось перехватить отправленную моим клиентом команду.

Но дальше пока не пошло. Навскидку имеется две проблемы.

Первая. Клиент передает команду на сервер так:

LS := TStringList.Create;
LS.Add('Привет - это я!');          
ACommand := TTetheringCommand.Create('MyCommand', 33, ['par1','par2'], LS);
Resp := TAPClient.SendCommandWithResponse(TMClient.RemoteProfiles[0], ACommand);

На сервере в событии TAPServerAfterReceiveData эта команда перехватывается. Но я почему-то не могу вынуть переданный объект, а именно TStringList. Делаю так:
tc := TTetheringCommand.Create(TBytes(ADataBuffer));
 try
 memConnectedInfo.Lines.Add(tc.ToString);// TStringList(tc.Data)[0]
 if tc.Command = 'MyCommand'
  then
   begin
    memConnectedInfo.Lines.Add('Сообщ. ' + TStringList(tc.Data)[0]); 
    Resp := TTetheringCommand.Create('RetMyCommand', 3, [], tc.Data);
    Result := TByteDynArray(Resp.ToBytes); //это ни на что не влияет
   end
  else Result := ADataBuffer;
 except
  Result := ADataBuffer;
 end;

Срабатывает исключение при обращении TStringList(tc.Data)[0]. Что я делаю не так? Или в ADataBuffer объект отсутствует? На клиенте команда 'RetMyCommand' тоже получается, опять не могу получить данные переданного объекта. Правда делается это в событии TAPServerBeforeSendData:

 tc := TTetheringCommand.Create(TBytes(ADataBuffer));
 try
 memConnectedInfo.Lines.Add(tc.Command);
 if tc.Command = 'RES_BADCOM'
  then
   begin
    LS := TStringList.Create;
    LS.Add('Привет - это я с сервера!');
    Resp := TTetheringCommand.Create('RetMyCommand', 2, [], TObject(LS));
    Result := TByteDynArray(Resp.ToBytes);
    memConnectedInfo.Lines.Add(TTetheringCommand.Create(TBytes(Result)).ToString);
   end
  else Result := ADataBuffer;
 except

 end;

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

Проверка в TAPServerAfterReceiveData
 tc := TTetheringCommand.Create(TBytes(ADataBuffer));
 if tc.Data = nil возвращает ИСТИНУ. Объект действительно где-то пропал.

 

Изменено пользователем Wovan2
Дополнение
Ссылка на комментарий
  • 0
14 часов назад, Daniel Dorneles Peres сказал:

Ola.

Estava fazendo uma implementação usando Tethering e encontrei sua questão, mas tive de utilizar o google para traduzir, acho que terá de fazer o mesmo.

Também não gosto de usar socket (Indy) devido ao problema de não conseguir capturar a perda de conexão em algumas situações, o que acaba causando muitos problemas, então resolvi testar o Tether e até o momento estou gostando bastante. Estou utilizando recursos compartilhados, e tem se mostrado bem eficiente.

Peguei o seu caso pois estava tentando criar um log do que estava recebendo, e me deparei com o mesmo problema de parar o funcionamento dos recursos quando adiciono o evento AfterReceiveData. Fiz alguns testes e por tentativa e erro consegui fazer o código funcionar, embora não tenha entendido exatamente o porque do Result funcionar da forma como fiz, era uma tentativa para analisar os dados mas que acabou por funcionar.

Esse evento (AfterReceiveData) na verdade não reflete os dados que são modificados em tempo real, mas os recursos e ações que estão disponíveis em ambos os lados, pelo menos no que se refere aos recursos e ações "persistentes", acredito que para os recursos "transitórios" esse evento possa funcionar, mas não testei ainda.

Se colocar o código abaixo em um memo, conseguira entender um pouco do que quero dizer.

blah blah blah  

Espero ter ajudado de alguma forma.

 

 

Ola!

Guy, you are on Russian forum and almost nobody here understand your language. So please, i repeat: please, write on russian or on english.
And yeach, have a nice day! ?

Ссылка на комментарий
  • 0
В 03.11.2017 в 14:13, Wovan2 сказал:

Не могу найти ни одного примера использования. Даже в хелпе Delphi:huh:

Посмотрите в идущих в комплекте примерах:

Тут \Object Pascal\Multi-Device Samples\Device Sensors and Services\App Tethering\ :

  • MediaPlayer
  • PhotoWall

И тут \Object Pascal\RTL\Tethering\ :

  • BDShoppingList
  • DesktopBeaconCast
  • DesktopCast
  • MediaPlayer
  • PhotoWall

А в общих чертах как то так:

Вы получаете на "сервере" данные ни где нибудь, а в событии

procedure TForm1.TetheringAppProfile1ResourceReceived(const Sender: TObject;  const AResource: TRemoteResource);

Переменная AResource - все что вам нужно. Там и полученные данные AResource.Value определенного типа AResource.Value.DataType. И профиль отправителя AResource.Profile позволяющий точно его идентифицировать. 

 

 

Ссылка на комментарий

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить на вопрос...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...