Indy TCP-клиент в потоке

Следуя этой теме, я пытаюсь создать приложение C ++ Builder XE5 с:

  • основная форма
  • a TIdTCPClient
  • TThread для этого TIdTCPClient соединения, которое открывает сокет, отправляет запрос, а затем бесконечно ожидает нескольких ответов
  • действия, которые происходят в сокете, вызовут обновления в основной форме

Мне не удалось найти никаких примеров; Насколько я могу судить, все примеры, на которые есть ссылки со страницы Indy Demos, не используют никаких потоков в своих клиентах.

Мои вопросы:

  • Должен ли TIdTCPClient быть в основной форме (как компонент времени разработки) или он должен быть переменной-членом класса потока?
  • В событиях, запускаемых TIdTCPClient, нужно ли синхронизировать код в обработчиках событий (которые являются функциями-членами моей основной формы)?
  • Безопасно ли как для основного потока VCL, так и для клиентского потока выполнять вызовы функций для объекта TIdTCPClient?

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


person M.M    schedule 16.06.2015    source источник


Ответы (1)


Должен ли TIdTCPClient быть в основной форме (как компонент времени разработки) или он должен быть переменной-членом класса потока?

Либо будет работать нормально. Важно то, что вы вызываете Connect() и другие методы ввода-вывода в контексте рабочего потока (внутри его Execute() метода).

В событиях, запускаемых TIdTCPClient, нужно ли синхронизировать код в обработчиках событий (которые являются функциями-членами моей основной формы)?

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

Безопасно ли как для основного потока VCL, так и для клиентского потока выполнять вызовы функций для объекта TIdTCPClient?

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

На данный момент мой код заполнен временными переменными и функциями-заглушками, потому что Synchronize требует закрытия void (void), и это довольно спагетти.

Вы можете использовать классы Indy _3 _ / _ 4_, чтобы помочь вам лучше организовать этот спагетти-код. Например, унаследуйте класс от TIdSync, переместите в него свои переменные и переопределите его виртуальный метод DoSynchronize() для вызова ваших методов (ов) формы по мере необходимости. Затем вы можете создать экземпляр своего класса, при необходимости заполнить его переменные, вызвать его Synchronize() метод, прочитать его переменные, если необходимо, а затем освободить его.

#include <IdSync.hpp>

class TMySync : public TIdSync
{
protected:
    virtual void __fastcall DoSynchronize();
public:
    // variables...
};

void __fastcall TMySync::DoSynchronize()
{
    // call Form methods, use variables as needed...
}

void __fastcall TMyThread::Execute()
{
    //...
    TMySync *sync = new TMySync;
    // set variables as needed...
    sync->Synchronize();
    // read variables as needed...
    delete sync;
    //...
}
person Remy Lebeau    schedule 16.06.2015
comment
У TIdSync не было компонента, но я нашел его в ‹IdSync.hpp›. Похоже, он работает только с TIdThread (в настоящее время я использую TThread), поэтому я думаю, что должен попытаться выяснить, как они работают, на основе их документации API. - person M.M; 17.06.2015
comment
Нет, TIdSync - это не компонент, а просто класс. И нет, вам не нужен TIdThread, чтобы его использовать. В XE5 это просто оболочка для статического метода TThread::Synchronize(). Не должно быть вообще никаких ссылок на TIdThread в IdSync.hpp. Для версий C ++ Builder, предшествующих CB2005, это возможно, но вы все равно можете использовать TIdSync без использования TIdThread (он просто создает его для внутреннего использования). - person Remy Lebeau; 17.06.2015