Получение Данных В Потоке

Тема в разделе "Delphi - Сети", создана пользователем Shouldercannon, 3 фев 2012.

  1. Shouldercannon

    Shouldercannon Well-Known Member

    Регистрация:
    25 май 2010
    Сообщения:
    125
    Симпатии:
    0
    Задача:
    Подключиться к серверу и слушать, что он пришлёт до завершения работы приложения. Прослушка должна быть обязательно в отдельном потоке, иначе форма повиснет.
    Код (Delphi):
    procedure TFormMain.BConnectClick(Sender: TObject);
    var
    My_Thread: TMy_Thread;
    begin
    IdTCPClient1.Host := '77.108.194.247';
    IdTCPClient1.Port := 80;
    IdTCPClient1.Connect(1000);

    My_Thread := TMy_Thread.Create(True);
    My_Thread.FreeOnTerminate := False;
    My_Thread.GoMemo := Memo1;
    My_Thread.Resume;
    end;

    procedure TMy_Thread.Execute;
    begin
    while not Terminated do
    begin
    if FormMain.IdTCPClient1.Connected then
    begin
    s := FormMain.IdTCPClient1.ReadLn(); // Показывает сюда
    Synchronize(SyncProc);
    end;
    end;
    end;

    procedure TMy_Thread.SyncProc;
    begin
    GoMemo.Lines.Add('[' + TimeToStr(Now) + '] - IdTCPClient1: ' + s);
    end;
    При закрытии формы появляется ошибка на строке
    Код (Delphi):
    s := FormMain.IdTCPClient1.ReadLn();
     

    Вложения:

    • error.jpg
      error.jpg
      Размер файла:
      83 КБ
      Просмотров:
      58
  2. -master-

    -master- Well-Known Member

    Регистрация:
    14 янв 2012
    Сообщения:
    629
    Симпатии:
    18
    Ну а чего вы хотите? у вас поток продолжает работать, а формы уже нет, тут все что хотите может быть.
     
  3. Shouldercannon

    Shouldercannon Well-Known Member

    Регистрация:
    25 май 2010
    Сообщения:
    125
    Симпатии:
    0
    Прошу помощи разобраться с этой проблемой.
     
  4. -master-

    -master- Well-Known Member

    Регистрация:
    14 янв 2012
    Сообщения:
    629
    Симпатии:
    18
    Так я уже все объяснил.
    Поток должен быть сам по себе, а у вас он активно работает с vcl. Это и есть мина, она рванет в любом случае, ранно или поздно, и не зависит от нашего желания.

    Отделяйте мух от котлет. Форма сама по себе, поток сам по себе.
    Либо надо делать полностью управляемый поток, и все руками контролировать.
     
  5. Shouldercannon

    Shouldercannon Well-Known Member

    Регистрация:
    25 май 2010
    Сообщения:
    125
    Симпатии:
    0
    Другой подход. Ошибка осталась тажа плюс появилась новая.
    Имеющаяся - Not connected
    Новая - THread Error: отказано в доступе (5)
    Код (Delphi):
    ...
    TMyThread = class(TThread)
    private
    { Private declarations }
    s: string;
    protected
    procedure Execute; override;
    procedure ReadFromSocket;
    procedure SyncProc;
    public
    GoMemo: TMemo;
    end;
    ...
    var
    FormMain: TFormMain;
    MyThread: TMyThread;
    ...
    procedure TFormMain.FormCreate(Sender: TObject);
    begin
    MyThread := TMyThread.Create(True);
    MyThread.GoMemo := Memo1;
    end;

    procedure TFormMain.BConnectClick(Sender: TObject);
    begin
    IdTCPClient1.Host := '77.108.194.247';
    IdTCPClient1.Port := 80;
    IdTCPClient1.Connect(1000);
    end;

    procedure TFormMain.BDisconnectClick(Sender: TObject);
    begin
    IdTCPClient1.Disconnect;
    end;

    procedure TMyThread.Execute;
    begin
    while not Terminated do ReadFromSocket;
    end;

    procedure TMyThread.ReadFromSocket;
    begin
    s := FormMain.IdTCPClient1.ReadLn; // ==> Not connected
    Synchronize(SyncProc);
    end;

    procedure TMyThread.SyncProc;
    begin
    GoMemo.Lines.Add('[' + TimeToStr(Now) + '] - IdTCPClientMSG: ' + s);
    end;

    procedure TFormMain.IdTCPClient1Connected(Sender: TObject);
    begin
    Memo1.Lines.Add('[' + TimeToStr(Now) + ']: IdTCPClient1 подключен');

    MyThread.Resume;
    end;

    procedure TFormMain.IdTCPClient1Disconnected(Sender: TObject);
    begin
    Memo1.Lines.Add('[' + TimeToStr(Now) + ']: IdTCPClient1 отключен');

    MyThread.Suspend; // ==> THread Error: отказано в доступе (5)
    end;

    end.
     

    Вложения:

  6. -master-

    -master- Well-Known Member

    Регистрация:
    14 янв 2012
    Сообщения:
    629
    Симпатии:
    18
    Все правильно, вы ничего не исправили, все осталось как было, а то что добавили, привело к другой ошибки.

    Смотрите у вас при закрытии формы поток продолжает работать, его ж никто не рубит, а он стучится к форме, поскольку формы уже нет, то что остается? только ошибка.
    И вообще все формы компоненты и т.п. vcl, потоко-зависимы, т.е. просто так обращаться к ним из доп потока чревато, ошибки практически не избежать.

    Все чтонадо потоку, как правило создаютвконтексте доп потока, а с основным потоком, делают межпотоковое взаимодействие, т.е. применяют некий механизм, например сообщения.
     
  7. Shouldercannon

    Shouldercannon Well-Known Member

    Регистрация:
    25 май 2010
    Сообщения:
    125
    Симпатии:
    0
    Тупик. От ошибки с потоком избавился, а ошибка коннекта осталась, может, эта ошибка так и должна быть. Ткните пальцем в коде, где нужно внести поправки :(.
    Код (Delphi):
    ...
    TMyThread = class(TThread)
    private
    { Private declarations }
    s: string;
    protected
    procedure Execute; override;
    procedure SyncProc;
    public
    GoIdTCPClient: TIdTCPClient;
    GoMemo: TMemo;
    end;
    ...
    var
    MyThread: TMyThread;
    ...
    procedure TFormMain.BConnectClick(Sender: TObject);
    begin
    IdTCPClient1.Host := '77.108.194.247';
    IdTCPClient1.Port := 80;
    IdTCPClient1.Connect(1000);
    end;

    procedure TFormMain.BDisconnectClick(Sender: TObject);
    begin
    IdTCPClient1.Disconnect;
    end;

    procedure TMyThread.Execute;
    begin
    while not Terminated do
    begin
    if GoIdTCPClient.Connected then
    begin
    s := GoIdTCPClient.ReadLn;
    Synchronize(SyncProc);
    end;
    end;
    end;

    procedure TMyThread.SyncProc;
    begin
    GoMemo.Lines.Add('[' + TimeToStr(Now) + '] - IdTCPClientMSG: ' + s);
    end;

    procedure TFormMain.IdTCPClient1Connected(Sender: TObject);
    begin
    Memo1.Lines.Add('[' + TimeToStr(Now) + ']: IdTCPClient1 подключен');

    MyThread := TMyThread.Create(True); // Останавливаем поток
    MyThread.GoIdTCPClient := IdTCPClient1;
    MyThread.GoMemo := Memo1;
    MyThread.Resume; // Запуск потока
    end;

    procedure TFormMain.IdTCPClient1Disconnected(Sender: TObject);
    begin
    Memo1.Lines.Add('[' + TimeToStr(Now) + ']: IdTCPClient1 отключен');

    MyThread.FreeOnTerminate := False; // По завершению кода поток не завершится
    MyThread.Terminate;
    end;
    По идее, после нажатия на кнопку BDisconnect произойдёт Disconnect и поток уничтожиться. если даже уничтожить поток перед
    Код (Delphi):
    IdTCPClient1.Disconnect;
    , то всёравно возникает ошибка подключения.
     
  8. sinkopa

    sinkopa Well-Known Member

    Регистрация:
    17 июн 2009
    Сообщения:
    344
    Симпатии:
    9
    Так нельзя. GoIdTCPClient.Connected станет false только по завершении процедуры IdTCPClient1Disconnected(Sender: TObject);
    Получается, что Вы пытаетесь в "своем потоке" управлять "чужим" потоком из обработчика события (который вообще то сам должен через синхонайз быть) рожденного кодом исполняющимся в "чужом" потоке...

    Сначала "отпустить" поток, а потом уже дисконектиться... только так.
    Код (Delphi):
    procedure TFormMain.BDisconnectClick(Sender: TObject);
    begin

    MyThread.Terminate;
    Sleep(200); // Какое то время требуется для завершения итерации внутреннего цикла потока (в это время IdTCPClient может получать данные с сервера)
    while not MyThread.Terminated do
    begin
    Sleep(20);
    Application.ProcessMessages;
    end;

    IdTCPClient1.Disconnect;
    end;
     
Загрузка...

Поделиться этой страницей