Indy Server и ADOQuery конфликтуют

#sql #delphi #delphi-7 #indy #tadoquery

#sql #delphi #delphi-7 #indy #tadoquery

Вопрос:

У меня есть две программы, одна из которых является клиентом, а другая — сервером для клиента. Клиент отправляет некоторые данные на сервер следующим образом, а затем считывает ответ:

  idtcpclient1.WriteLn(command); //Command contains data that the server needs eg. name and surname
 progressbar1.StepIt;
 sresult := idtcpclient1.ReadLn();
  

Затем сервер считывает строку, обрабатывает ее и создает SQL-запрос.

 adoquery1.Close;
adoquery1.SQL.Text := 'select * from ' sGrade;
adoquery1.Open;
  

Но как только он открывает соединение с базой данных, клиент выдает ошибку «Соединение закрыто корректно»

Я протестировал код сервера без клиента, имитируя ввод, и он работает нормально.

Я думаю, что Indy и ADOQuery конфликтуют, если да, то почему и как я могу это исправить

Если нет, то в чем проблема и как я должен ее исправить?

Комментарии:

1. Какой порт вы используете для связи с сервером при использовании Indy?

2. Проблема в том, что код Indy server выполняется в потоке вне основного потока. Вам необходимо создать свое соединение / запрос в контексте потока indy. Или используйте Synchronize для выполнения кода БД в контексте основного потока.

3. Я использую порт: 55555

4. @whosrdaddy Я не уверен, как использовать «Синхронизировать», можете ли вы подробнее рассказать о том, как это сделать

Ответ №1:

ADO использует COM-объекты с общим потоком, которые имеют сходство с потоком, который их создает. Они не могут использоваться через границы потоков, если они не маршалированы.

TCP-сервер Indy является многопоточным. Каждый клиент выполняется в своем собственном потоке.

Поток должен вызвать CoInitialize/Ex() , чтобы установить свою связь с COM, прежде чем он сможет получить доступ к любым COM-объектам, и вызвать CoUninitialize() , когда это будет сделано с помощью COM.

Ваш сервер выходит из строя, потому что он вызывает неперехваченное исключение, которое отключает клиент. Скорее всего, потому, что вы не инициализировали COM.

Вам необходимо создавать объекты ADO для каждого клиента, не используйте их из основного потока. В OnConnect событии сервера вызовите CoInitialize/Ex() . В этом OnDisconnect случае вызовите CoUninitialize() . В этом OnExecute случае динамически создавайте и используйте новые объекты ADO по мере необходимости.

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

Ответ №2:

Если вы используете datamodules: вы можете создать один экземпляр datamodule для каждого клиента, чтобы избежать ошибок обработки потоков. Indy может содержать ссылку на datamodule клиента в контексте. Или используйте пул экземпляров datamodule, в зависимости от доступных ресурсов и трафика.