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

Wovan2

Пользователи
  • Постов

    45
  • Зарегистрирован

  • Посещение

Сообщения, опубликованные Wovan2

  1. 1 час назад, Rusland сказал:

    При обрыве соединения и переподсоединении будет новый контекст :)

    Разумеется и новый ответ. А первое соединение должно закрыться по ошибке. Видимо.

  2. 1 час назад, Rusland сказал:

    Как различать клиентов между собой? При каждом пакете клиенту сообщать свой уникальный номер?

    На сервере проблем в этом нет. Событие procedure IdTCPServerExecute(AContext: TIdContext) в параметре принимает контекст соединения. Там вся информация о соединении инициировавшем это событие.

  3. 12 минуты назад, Rusland сказал:

    @Wovan2, после подключения клиента к серверу, занимаемая сервером память подскакивает до 1Гб :)

    Ну это вопрос к Indy. Моего кода в приложении очень мало.

    Indy утверждает, что для каждого подключения создается отдельный поток, который обрабатывает это соединение, что впрочем, логично

    Знаете. Сейчас посмотрел. Сервер запущен на Win10. Без подключений 8.2 Мб. Один клиент 8.3 Мб. Два клиента - тоже 8.3 Мб.

  4. 11 час назад, POV сказал:

    Всё же ты придёшь к потоку ))

    Для меня потоки не новость. Работать с ними приходилось. Но в данном случае это как-то усложняет все дело.

    10 часов назад, kami сказал:

    Я все-таки повторю свой вопрос: если в одной из реализаций ты пришел к взаимодействию вида запрос-ответ-разрыв связи, то почему не использовать http вместо tcp?

    Еще потерять кучу времени, чтобы понять как работают новые компоненты?

    На данный момент я убрал или сделал проверки на существование внутренних объектов IdTCPClient и IdTCPServer, где они проскакивали в коде - вываливания и на сервере и на клиенте прекратились. Подключение проверяю при каждом обращении к серверу, при отсутствии происходит переподключение.

  5. Перед долгим кодом делал

     r1.Visible:= true; //TRectangle
     r1.BringToFront;
     ai1.Enabled := true;

    В конце

      ai1.Enabled := false;
      r1.Visible:= false;

    В результате вообще ничего не видно. 

    Ну почему все так не очевидно и не понятно. Неужели какой-нибудь стандартной анимашки нет??? Пробовал и через BitmapListAnimation1.Enabled := true; Результат примерно такой же отображается первый кадр и все. Может через поток надо как-то это делать??? Блин по полдня надо тратить на тривиальные вещи

  6. Просветите, пожалуйста, насчет IOHandler. Я явно его не задаю, однако код IdTCPClient.IOHandler.Write(s, s.Size, True); отрабатывает без ошибок и корректно. Нужно его задавать явно?

    И еще на сервере ошибка происходит при закрытии формы на коде 

    if Assigned(IdTCPServer)
      then IdTCPServer.Active := False;

    а именно на IdTCPServer.Active := False, поскольку сам объект существует. (ошибка обращения к памяти, посмотрел по отладчику пару раз проходит по exception и в конце концов AV). Если убрать вообще остановку сервера, то при закрытии ошибок нет. Интересно как в этом случае насчет утечки памяти?

  7. В 17.11.2017 в 16:57, Rusland сказал:

    TimerTimer(nil); - вот это что такое? Почему nil?

    Не знаю как в D10 в D7 это просто вызов процедуры с пустым параметром. Формально туда можно было засунуть Sender от вызывающей процедуры, если бы этот параметр как-то обрабатывался в TimerTimer. А раз он никак не обрабатывается, то можно втиснуть пустышку.

  8. В 18.11.2017 в 21:38, Fedor K сказал:

    Не используйте FormActivate событие

    Вариант обхода с помощью стартового таймера, в общих чертах понял.

    В 18.11.2017 в 21:38, Fedor K сказал:

    TIniFile нет смысла использовать каждый раз для считывания настроек

    Я, собственно, и читаю этот файл один раз. Второй раз, что встречается в коде, это изменение настроек в этом файле. Возможно используется 1 раз за все время жизни программы.

    В 18.11.2017 в 21:38, Fedor K сказал:

    Хранить настройки в компонентах (edSettingHost.Text и т.п.).

    И это есть в коде. Хотя и не совсем красиво. В Window я обычно так не делаю.

     

    В 18.11.2017 в 21:38, Fedor K сказал:

    TCP сокет соединения следуют принимать как асинхронные, а не как запрос-ответ. Это предусматривает получение команды сервером, какое-то выполнение и лишь потом отправка на клиент. Поэтому попробуйте отказаться от использования GetFromServer.

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

    На клиенте потоки используются исключительно для уменьшения подвисаний интерфейса программы? Ведь соединение с сервером принципиально одно.

    Спасибо за проявленную заинтересованность:)

  9. 15 минут назад, Rusland сказал:

    вызывает ошибку, если клиент не достучался до сервера.

    Согласен. Здесь поторопился. Если нет соединения, то и свойства все эти - швах. Надо просто свойства клиента Host и Port. Спасибо. Но основная проблема, я так подозреваю, не в этом.

  10. 46 минут назад, Rusland сказал:

    Отступ в 1 пробел - это зло

    Привычка, выработанная годами:huh: Маленький монитор как бы способствует

    В Delphi 10 плохо разбираюсь в файлах проекта. Запаковал всю папку проекта. Но кода, конечно, стало больше. Спасибо за проявленное внимание.

     

    Socket.7z

  11. 2 часа назад, POV сказал:

    Нефиг в таймере этот код располагать, всё в поток

    На самом деле таймер я подготовил, но не использую (не активирую) его. Просто один раз вызываю в начале его функцию TimerTimer.

    1 час назад, Fedor K сказал:

    Можете мне сделать тестовый сервер и клиент, чтобы я смог у себя проверить? Тогда мой ответ будет более детальным.

    Добавил файлы. Код довольно короткий. Частности по работе с данными убрал. Все что касается работы клиента и сервера осталось. Напомню Сервер приложение Win32 VCL. Клиент приложение для Abdroid FMX. Пакеты данных размером от нескольких десятков байт до 5 килобайт максимум и редко.

     

    1 час назад, Fedor K сказал:

    procedure T<какое-то имя класа>.Read;

    Это процедура срабатывания таймера?

    Desktop.7z

  12. 17 часов назад, Akad сказал:

    P.S. Если ты осознанно отправляешь AnsiString

    В том то и дело, что до настоящего времени я это делал неосознанно. Понятно, что каждая сторона канала должна работать на понятной ей кодировке. Сейчас, с Вашей помощью, я достиг некоторого понимания вопроса, и проблема рассосалась. Спасибо. Тот код, что выложил я тоже вполне себе работоспособен.

     

    3 часа назад, kami сказал:

    Пусть хоть китайской традиционной считает. Повторюсь - абсолютно без разницы, что за кодировка внутри приложения. Главное, чтобы общение (ввод/вывод) с внешним миром шло с явным указанием кодировки, поскольку автоопределение и/или считание кодировкой по умолчанию рано или поздно приведет к фейлу.

    Ну, собственно, что-то подобное я и сделал.  Автоопределение, согласен, крайне ненадежная штука.

  13. 1 час назад, POV сказал:

    INDY и TCP вполне себе дружат. На винде попробуй сначала.

    Наверное должны дружить, раз написаны компоненты.

    На Windows что проверять там связь стабильная. На Android из-за непостоянности связи происходят всякие непонятные зависоны,то на сервере, то на клиенте. Тонкостей Indy не знаю, к сожалению. Наверняка есть какой-то алгоритм, ну там последовательность вызовов всяких там индийских событий и функций для обеспечения стабильности работы в нестабильной сети. Разбираться в нюансах ну очень долго и не продуктивно для разового применения в простеньком  приложении. Подозреваю, что обеспечение стабильности связи займет больше кода, чем само приложение...

  14. А разве в Indy не реализована многопоточность в самих компонентах? Я так понял из описания компонентов.

    И Android  как-то не понятно отрабатывает блоки try.

    Наверное у кого-то уже есть наработки по управлению соединениями в Indy? Ну там, как проверить соединение, как отработать разрыв связи и т.п. Пока получается стабильная работа так: соединение создается перед командой и закрывается сразу после ответа. 

     

  15. Доброе время суток.

    Борюсь с Indy 10 на FMX. Обмен данными между сервером и клиентом наладил. Все работает стабильно.

    Стал экспериментировать с разрывом связи. И тут программы ведут себя не очень понятно, особенно на клиенте. Если сервер не запушен. Клиент на команде IdTCPClient.Connect; закрывается. ???? Делаю обработки так
     

    procedure TfrmMainClient.TimerTimer(Sender: TObject);
    var
     Server : string;
    begin
     if not IdTCPClient.Connected
      then
       try
        IdTCPClient.Connect;
       except
       on E : Exception do
        lblInfo.Text := e.Message;
       end;
     Server := 'Сервер ' + IdTCPClient.Socket.Binding.PeerIP +
               ':' + IntToStr(IdTCPClient.Socket.Binding.PeerPort);
     if IdTCPClient.Connected
      then
       begin
        lblInfo.Text := Server + ' подключен!';
        lblInfo.TextSettings.FontColor := TAlphaColors.Green;
       end
      else
       begin
        lblInfo.Text := Server + ' не доступен!';
        lblInfo.TextSettings.FontColor := TAlphaColors.Red;
       end;
    end;

    Никаких сообщений не появляется. Программа подвисает вместе с Адроидом, потом тупо окно закрывается. Молча. Таймауты на клиенте выставил ConnectTimeOut = 5000; ReadTimeOut = 5000;
    В общем вопрос. Как правильно организовать на Indy управление соединением? Чтобы не тормозило, Была возможность переподключиться. 

    PS. Почему-то в Delphi 10.2 не могу найти компонент AntiFreeze. ????

  16. 1 час назад, Akad сказал:

    Какая разница что там внутри?

    Как какая? Android по умолчанию искренне считает, что там UTF8. И в сеть выбрасывает UTF8.

    Сделал, на мой взгляд, довольно компактно.

    Клиент

    function TfrmMainClient.GetFromServer(Command : string) : string;
    var
     s : TStringStream;
    begin
     s := TStringStream.Create('', TEncoding.UTF8);
     try
     //запрос на сервер
        s.WriteString(Command);
     s.Position := 0;
        IdTCPClient.IOHandler.Write(s, s.Size, True);
        s.Clear;
     //читаем ответ сервера
     IdTCPClient.IOHandler.ReadStream(s);
     s.Position := 0;
     Result := s.ReadString(s.Size);
     finally
      if Assigned(s)
       then s.Free;
     end;
    end;

    Сервер

    procedure TfrmMainServer.IdTCPServerExecute(AContext: TIdContext);
    var
     s : TStringStream;
     Command, Param1, Param2 : string;
     Response : string;
    procedure ResponseClient(Response : string);
    begin
     s.WriteString(Response);
     s.Position := 0;
     AContext.Connection.IOHandler.Write(s, s.Size, True);
    end;
    begin
     s := TStringStream.Create('', TEncoding.UTF8);
     mem.Lines.Add(AContext.Connection.Socket.Binding.PeerIP);
     AContext.Connection.IOHandler.ReadStream(s);
     s.Position := 0;
     Command := s.ReadString(s.Size);
     mem.Lines.Add(Command); //Utf8ToAnsi
     SeparateNameValue(Command, ':', Command, Param1);
     s.Clear;
    //реакция на разные команды клиента
     case AnsiIndexStr(Command, ['GETISPOOLEXISTS', 'UPDATEISSET', 'GETCELLS']) of
     0:begin
    //тут код получения строки Response
        ResponseClient(Response);
       end;
     1:begin
    //тут код получения строки Response
        ResponseClient(Response);
       end;
     2:begin
    //тут код получения строки Response
        ResponseClient(Response);
       end;
      end;
     s.Free;
    end;

    С кодировкой проблем нет. Спасибо всем, кто откликнулся и помог. Объекты перегоняю через JSON.

    59 минут назад, kami сказал:

    Нет, на Windows - UTF-16

    Спасибо. Вот не знал.

  17. 27 минут назад, Anatoliy сказал:

    В событие OnConnect и будут русские буквы.

    
    //C++ Builder
    void __fastcall TFormPrint::IdTCPServer1Connect(TIdContext *AContext)
    {
     AContext->Connection->IOHandler->DefStringEncoding = IndyTextEncoding_UTF8();
    }

     

    Спасибо. Все это конечно хорошо, но уж больно далеко и не интуитивно.

  18. Здравствуйте. Хотелось бы поделиться своим пониманием проблемы кодирования строк. Может я что-то не понимаю. Чтобы как-то прояснить для себя.

    Тип string в delphi и кодировка символов, это две разные вещи. String (в Delphi 10 по сути это UnicodeString) - это указание компилятору сколько памяти выделить под переменную, заданного типа. Для Delphi 10 это 2 байта на символ. А что конкретно в этих байтах - это уже кодировка. Латиница практически во всех кодовых таблицах имеет они и те же коды (в unicode первый байт заполнен нулями). Поэтому с ней и проблем, практически не бывает. Кириллица же в разных кодовых таблицах имеет разные коды. Из-за этого и все проблемы. Это все понятно.

    Мне не понятно, например, в какой кодировке хранится текст в таком коде:
    var s : string:
    s := 'Привет';

    Это зависит, видимо от ОС, в которой запущено приложение. На Android, по видимому, это UTF8. На Windows - ANSI(первый байт 0). Но это по наитию. Как все же правильно работать с кодировками, чтобы всегда знать, в какой кодировке находятся строки в которыми ты работаешь в данный конкретный момент, на данном конкретном компе? Если это понять, то скорее всего и проблемы с "крякозяблами" должны пропасть сами собой. 

    Вы согласны? Поделитесь пожалуйста своими соображениями, кто в курсе. Спасибо.

  19. Спасибо. Действительно, если при создании потока указать s := TStringStream.Create('', TEncoding.UTF8), то все пляски с перекодировками оказываются не нужными. В общем первоначальный код работает с указанной поправкой корректно.

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