rust gg Опубликовано 28 апреля, 2018 Опубликовано 28 апреля, 2018 Здравствуйте. На клиенте происходит прием и отрисовка (OnPaint) на Canvas на основании принятых данных с сервера . Сервер: отправляет в таймере, в таймере цикл отправки данных. Клиент принимает в таймере. Когда данных отправленных сервером не большое количество отрисовка проходит нормально, когда приходит частое количество пакетов, начинает приложение клиента тормозить. Думаю капать в сторону потока. Вопрос tcpclient вещать в поток или отрисовку? Попробовал tcpclient засунуть в поток, но ничего не выходит. type TMyThread = class(TThread) Progress: string; Client : TIdTCPClient; procedure SetProgress; constructor Create; private protected procedure Execute; override; end; TRec_Data = record Flag: array[0..20] of char; end; implementation uses ClientForm; constructor TMyThread.Create; var Rec: TRec_Data; Buffer: TIdBytes; begin inherited Create(true); Client := TIdTCPClient.Create(nil); Client.Host := '127.0.0.1'; Client.Port := 6000; Client.Connect; // Передаем данные if Client.Connected = True then begin Rec.Flag := 'addUser'; Buffer := RawToBytes(Rec, SizeOf(Rec)); Client.IOHandler.Write(Buffer); end; end; procedure TMyThread.Execute; var Rec: TRec_Data; Buffer: TIdBytes; begin while (Client.Connected) do begin Client.IOHandler.ReadBytes(Buffer, SizeOf(Rec)); BytesToRaw(Buffer, Rec, SizeOf(Rec)); Progress := Rec.Flag; Synchronize(SetProgress); end; end; procedure TMyThread.SetProgress; begin Form1.Memo1.Lines.Insert(0, Progress); end; При таком варианте поток отрабатывает сообщения с сервера, но видит выводит только первый ответ с сервера. Помогите плиз... Цитата
0 kami Опубликовано 28 апреля, 2018 Опубликовано 28 апреля, 2018 2 часа назад, rust gg сказал: когда приходит частое количество пакетов, начинает приложение клиента тормозить. Так не вызывайте отрисовку на каждый принятый пакет. Пусть принятые данные кладутся в очередь (например - TQueue). Когда назревает необходимость отрисовки (допустим, по таймеру) - из очереди выгребаются все пакеты и данные рисуются сразу, всем скопом. По потоку: в соответствии с общими правилами - некорректно создавать объект в одном потоке и начинать его использовать в одном потоке, а основное использование вести в другом. Это я про TIDTCPClient. Перенесите его создание и уничтожение (кстати - а где деструктор?) в Execute вашего потока. 2 часа назад, rust gg сказал: поток отрабатывает сообщения с сервера, но видит выводит только первый ответ с сервера На основании чего такой вывод? Я про первую часть - "поток отрабатывает сообщения с сервера"? Цитата
0 rust gg Опубликовано 28 апреля, 2018 Автор Опубликовано 28 апреля, 2018 (изменено) отрисовку я не вызываю на каждый пакет, она происходит в таймере и в таймере же происходит принятия пакетов с сервера и тут возникает очередь (это вариант без потока) "поток отрабатывает сообщения с сервера" - например сервер шлет три сообщения с разными flag, а в мемо попадает три раза одно и тоже, самое первое. 17 минут назад, kami сказал: Перенесите его создание и уничтожение (кстати - а где деструктор?) в Execute вашего потока. Перенесу, но от этого ничего не меняется. Изменено 28 апреля, 2018 пользователем rust gg Цитата
0 Евгений Корепов Опубликовано 29 апреля, 2018 Опубликовано 29 апреля, 2018 Накидал вам пример с использование потокобезопасной очереди. Логика работы такая - поток получает данные и заталкивает их в очередь, в главной форме, в таймере (можно изменить на OnIdle), проверяем очередь на наличие данных, если данные есть, то обрабатываем их. Обратите внимание на процедуру создания очереди - FQueue:=TThreadedQueue<TRec_Data>.Create(100, 1000, 10); где первый параметр размер очереди (100), второй таймаут заталкивания данных в очередь (1000мс = 1сек), третьй таймаут вытаскивания из очереди (10 мс - маленький, чтоб таймер у нас не подвисал в ожидании). Вот код проекта целиком unit Unit1; interface uses System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, System.Generics.Collections, IdTCPClient, IdGlobal, FMX.Controls.Presentation, FMX.ScrollBox, FMX.Memo; type TRec_Data = record Flag: array[0..20] of char; end; TMyThread = class(TThread) private Progress: string; Client : TIdTCPClient; FQueue : TThreadedQueue<TRec_Data>; protected procedure Execute; override; public constructor Create(const AQueue : TThreadedQueue<TRec_Data>); destructor Destroy; override; end; TForm1 = class(TForm) procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); private { Private declarations } FQueue : TThreadedQueue<TRec_Data>; FMyThread : TMyThread; Timer : TTimer; procedure OnTimer(Sender: TObject); public Memo1: TMemo; { Public declarations } end; var Form1: TForm1; implementation {$R *.fmx} procedure TForm1.FormCreate(Sender: TObject); begin FQueue:=TThreadedQueue<TRec_Data>.Create(100, 1000, 10); Timer:=TTimer.Create(Self); Timer.Interval:=100; Timer.OnTimer:=OnTimer; Timer.Enabled:=True; FMyThread:=TMyThread.Create(FQueue); FMyThread.Start; end; procedure TForm1.FormDestroy(Sender: TObject); begin if Assigned(FMyThread) then begin FMyThread.Terminate; FMyThread.WaitFor; FMyThread.Free end; if Assigned(Timer) then Timer.Free; if Assigned(FQueue) then FQueue.Free; end; procedure TForm1.OnTimer(Sender: TObject); Var ARec : TRec_Data; begin // while FQueue.PopItem(ARec) = TWaitResult.wrSignaled do или if FQueue.PopItem(ARec) = TWaitResult.wrSignaled then Form1.Memo1.Lines.Insert(0, ARec.Flag); end; constructor TMyThread.Create(const AQueue : TThreadedQueue<TRec_Data>); var Rec: TRec_Data; Buffer: TIdBytes; begin inherited Create(true); FQueue:=AQueue; Client := TIdTCPClient.Create(nil); Client.Host := '127.0.0.1'; Client.Port := 6000; Client.Connect; // Передаем данные if Client.Connected = True then begin Rec.Flag := 'addUser'; Buffer := RawToBytes(Rec, SizeOf(Rec)); Client.IOHandler.Write(Buffer); end; end; destructor TMyThread.Destroy; begin if Assigned(Client) then Client.Free; inherited; end; procedure TMyThread.Execute; var Rec: TRec_Data; Buffer: TIdBytes; begin while Not Terminated do begin if Client.Connected then begin Client.IOHandler.ReadBytes(Buffer, SizeOf(Rec)); BytesToRaw(Buffer, Rec, SizeOf(Rec)); Progress := Rec.Flag; // Synchronize(SetProgress); FQueue.PushItem(Rec); end else Client.Connect; TThread.Sleep(10); end; end; end. Так же обратите внимание, я переписал ваш метод Execute на правильный. В вашей реализации, поток завершался при потере соединения. Rust Gabs и #WAMACO 2 Цитата
0 Rust Gabs Опубликовано 22 ноября, 2018 Опубликовано 22 ноября, 2018 (изменено) получилось спасибо Изменено 25 ноября, 2018 пользователем Rust Gabs Цитата
Вопрос
rust gg
Здравствуйте.
На клиенте происходит прием и отрисовка (OnPaint) на Canvas на основании принятых данных с сервера .
Сервер: отправляет в таймере, в таймере цикл отправки данных.
Клиент принимает в таймере.
Когда данных отправленных сервером не большое количество отрисовка проходит нормально, когда приходит частое количество пакетов,
начинает приложение клиента тормозить.
Думаю капать в сторону потока.
Вопрос tcpclient вещать в поток или отрисовку?
Попробовал tcpclient засунуть в поток, но ничего не выходит.
При таком варианте поток отрабатывает сообщения с сервера, но видит выводит только первый ответ с сервера.
Помогите плиз...
4 ответа на этот вопрос
Рекомендуемые сообщения
Присоединяйтесь к обсуждению
Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.