Russian Qt Forum
Октябрь 16, 2018, 03:46 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2 3   Вниз
  Печать  
Автор Тема: QTcpSocket и QThread  (Прочитано 2720 раз)
Harlon
Новичок

Offline Offline

Сообщений: 39


Просмотр профиля
« : Июнь 05, 2018, 11:07 »

Не без помощи хороших людей с этого форума, я написал сервер микроконтроллера и клиент на QT для Windows.

Описание сервера: сервер написан на "C" с использованием стэка LWIP, на него поступает запрос, он формирует массив int из 2048 значений и отправляет его на клиент.

Описание клиента: клиент написан на QT с использованием QTcpSocket, а делает он следующее: принимает массив от сервера, загоняет его в QVector <int>, записывает данные из QVector в файл и ещё с использованием QtCharts отрисовывает график полученных значений. Всё это делается нажатием на кнопку, которая генерирует запрос на сервер (пакует в QTcpSocket текст запроса и отправляет на сервер.)

И всё работает замечательно, но в клиенте теперь нужно сделать следующее:

Я должен добавить кнопку (предположим "Старт") и должен начать генерировать запросы на сервер и получать на клиенте с отрисовкой(но тут допустим можно и не каждый массив отрисовывать, а каждый 10, так как за секунду я должен получать 600 таких массивов) и записью в файл, от него ответы пока не нажму кнопку (предположим "Стоп").

Вопрос: можете ли вы подсказать в какую сторону копать, всё таки написать отдельный класс для такой реализации с использованием отдельного соккета и  использовать отдельный поток, возможно даже 2 (для отправки запроса и обработки данных) или же можно обойтись и основным потоком используя ещё что-то?
Записан
vic57
Чайник
*
Offline Offline

Сообщений: 77


Просмотр профиля
« Ответ #1 : Июнь 05, 2018, 14:56 »

а зачем тут лишние потоки? пока ты не получишь ответ - нечего рисовать. я когда-то делал имитатор РЛС по схеме клиент - сервер, там по кнопке Старт включался таймер, по таймеру шли запросы и по получению ответа шла отрисовка.
посмотри Fortune client/server
http://doc.crossplatform.ru/qt/4.5.0/qtnetwork.html#using-tcp-with-qtcpsocket-and-qtcpserver
« Последнее редактирование: Июнь 05, 2018, 15:12 от vic57 » Записан
Harlon
Новичок

Offline Offline

Сообщений: 39


Просмотр профиля
« Ответ #2 : Июнь 05, 2018, 16:04 »

То есть QTcpSoket::write() и redyread() создают отдельные потоки, и там обрабатывают всю инфу, не вешая GUI?
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5684


Жаждущий знаний


Просмотр профиля WWW
« Ответ #3 : Июнь 05, 2018, 16:21 »

Там нет потоков, это асинхронная работа.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
Harlon
Новичок

Offline Offline

Сообщений: 39


Просмотр профиля
« Ответ #4 : Июнь 05, 2018, 16:52 »

Всё осознал неправильность своей фразы. Но непонимание осталось. Я отправляю запрос примерно так:

Код
C++ (Qt)
void MainWindow::on_pushButtonSend_clicked()
{
   QByteArray block = 0;
   QString string;
   string = ui->lineEdit->text();
   block += string;
   controlsock->write(block);
}

тут я 1 раз нажимаю кнопку посылаю запрос

и в redyread() я получаю 2048 значений, тут же их обрабатываю и рисую.

Теперь я перепишу реализацию отправки, что бы кнопка при нажатии запускала таймер и по таймеру отправляла запрос, другой кнопкой я буду останавливать таймер, а redyread() не вешая основного потока будет это обрабатывать?
Записан
vic57
Чайник
*
Offline Offline

Сообщений: 77


Просмотр профиля
« Ответ #5 : Июнь 05, 2018, 18:06 »

readyRead - это сигнал, по его приходу выполняется какой-то код(слот)
Записан
Harlon
Новичок

Offline Offline

Сообщений: 39


Просмотр профиля
« Ответ #6 : Июнь 05, 2018, 18:48 »

Извиняюсь затупил... В сокете sockRead() выполняется код. А так как он находится в классе MainWindow, он будет вешать главный поток. + Ещё QChart в GraphicsView виджете работает, тут вообще всё повиснет...
Записан
vic57
Чайник
*
Offline Offline

Сообщений: 77


Просмотр профиля
« Ответ #7 : Июнь 05, 2018, 21:00 »

Извиняюсь затупил... В сокете sockRead() выполняется код. А так как он находится в классе MainWindow, он будет вешать главный поток. + Ещё QChart в GraphicsView виджете работает, тут вообще всё повиснет...
с чего это вдруг? имхо ты не понимаешь как QApplication работает
http://doc.crossplatform.ru/qt/4.7.x/qapplication.html#details
Записан
Harlon
Новичок

Offline Offline

Сообщений: 39


Просмотр профиля
« Ответ #8 : Июнь 06, 2018, 01:41 »

Всё разобрался, но есть проблема ещё одна, щас всё отрисовывается и принимается, но если скорость таймера повышаю, до 1.6 мс, то есть я должен буду принимать по 600 массивов по 8кб = 4.8 МБ/с, у меня начинают данные крошиться и значения из массива превращаются в хрен пойми что... 
Код
C++ (Qt)
QDataStream ds_can (socket);
   for (;;)
   {
 
       const auto bav = socket->bytesAvailable();
       if (bav < 8192 )
           return;
 
       QVector <int> canArr(2048);
       for (int i = 0; i < 2048; i++)
       {
           ds_can.setByteOrder(QDataStream::LittleEndian);
           ds_can >> canArr[i];
       }
... // далее отрисовка.
 

Даже если убрать отрисовку у меня всё равно значения разваливает...
Записан
vic57
Чайник
*
Offline Offline

Сообщений: 77


Просмотр профиля
« Ответ #9 : Июнь 06, 2018, 10:36 »

1. надо читать буфер, чтобы его очистить
Цитировать

if (bav < 8192 ) {
             stream->readAll();//clean buffer
             return;
}
2. QTimer стабильно будет работать с периодом >= 5 ms, тут надо алгоритм переделывать, вот тут может отдельный тред для сокета нужен(может даже ThreadPool).
 
« Последнее редактирование: Июнь 06, 2018, 10:42 от vic57 » Записан
Harlon
Новичок

Offline Offline

Сообщений: 39


Просмотр профиля
« Ответ #10 : Июнь 06, 2018, 20:29 »

Не спасло, если я помещаю socket->readAll() в условие, как вы написали, я начинаю терять большую часть данных ибо она стирается ещё раньше чем DataStream успевает их передать в массив. Я поставил очистку буфера сразу после того, как DataStream отработает, и на скорости 10-20 это спасает, но периодически всё равно попадается неверный массив(даже если слот не нагружать отрисовкой).

Вот как примерно выглядит нормальный массив:

QVector(502, -1766, -1285, 1130, 1167, 1350, -1212, 1115, 296, 1609, 829, -1732, -124, 1152, 772, 1971, 1537, 7, 474, -220, 1180, 1330, 715, 1081, 731, -74, 1158, 1421, 310, -1916, 1302, -268, -551, 1794, -780, -23, -1937, -958, -941, 1581, 493, -1216, -1038, -690, -400, 1712, -832, 940, 1380, 1215, 233, -1627, 205, -1695, -540, 756, -745, 1174, 683, -1545, 1059, 8, 1946, 367, -1003, 1289, -1398, 73, -429, 656, 1401, 1678, 1325, -1726, 758, 1028, -887, -1181, -1539, 1589, -1623, 633, -1881, -1121, 1514, -41, -801, -635, 1177, 785, 1276, 418, 220, -1814, 341, 317, 844, -1213, 1617, 1185, 836, -1099, -1526, 444, -272, -1424, -229, -1151, 960, 536, 1231, -136, -247, -955, 1857, -1472, 1612, -1524, -1233, 1262, 544, 1986, 135, -62, 1170, -749, 486, 585, -246, 1004, 1643, -1297, -447, -1658, 1771, -621, -134,...

А вот так выглядит массив, который разрушился:

QVector(1936748367, 0, 73364037, -101318656, 5701631, 24248320, -28246016, -17039361, -25624577, -72876033, -15204353, 42401791, -98697216, 25231359, 61079552, -24051712, -128188417, 33816575, -64159744, -63373313, -49610753, 105447423, -108331008, 104333311, -77463552, 116916223, 36569088, 2686976, 40960000, 29163520, -22478848, 15269887, 66650112, -37552128, 44105727, 50200576, 40632320, 2686976, -3080192, -8388609, 75431935, 18153472, -7274496, -52166657, -12845057, -125370369, -69337089, -28180481, -43122689, 92930047, -73465856, -111280129, 104529919, -34471936, 69533695, -103088128, 38535167, ...

Может есть мысли по чему на быстрой скорости так разрушается массив?
« Последнее редактирование: Июнь 06, 2018, 20:36 от Harlon » Записан
RedDog
Чайник
*
Offline Offline

Сообщений: 67


Просмотр профиля
« Ответ #11 : Июнь 06, 2018, 20:51 »

Почему бы не подписаться на readyRead() сокета, в нем вычитывать все что есть в сокете, и этот вычитанный кусок отправлять наверх, где отдельная логика его склеит/разрежет на нужное кол-во байт?
Записан
vic57
Чайник
*
Offline Offline

Сообщений: 77


Просмотр профиля
« Ответ #12 : Июнь 06, 2018, 21:04 »

Может есть мысли по чему на быстрой скорости так разрушается массив?
я бы сделал краш тест сети чисто на С без Qt
Записан
Harlon
Новичок

Offline Offline

Сообщений: 39


Просмотр профиля
« Ответ #13 : Июнь 06, 2018, 21:07 »

Дело то в том, что я понимаю если бы я по 30 мегабайт массивы разбирал, а у меня тут максимум при таком таймере максимум 1.6 МБ/с.

Это код отправки массива с сервера (эмуляция):
Код
C
for (int i = 0; i < 2048; i++)
{
n[i] = rand() % 4000 - 2000;
}
err = tcp_write(tpcb, n, 2048 * sizeof(int), 1);
 

Вот так я принимаю данные:

Код
C++ (Qt)
QDataStream ds_ascan (socket);
   int i;
   for (;;)
   {
       i++;
       const auto bav = socket->bytesAvailable();
       if (bav < 8192 )
       {
 
           return;
       }
 
       QVector <int> ascanArr(2048);
       for (int i = 0; i < 2048; i++)
       {
           ds_ascan.setByteOrder(QDataStream::LittleEndian);
           ds_ascan >> ascanArr[i];
       }
       socket->readAll();
... //дальше отрисовка и т.д.
 

Но даже убирая при таком варианте отрисовку, всё равно массив рушится...

На 2 разных устройствах пробовали и с реальным сигналом, всё равно рушится всё и напрямую подрубал к компу, у меня в интернет скорость выше в 2 раза чем в локалке с кабелем 1 метр. (имею ввиду при обмене через свою программу)
« Последнее редактирование: Июнь 06, 2018, 21:13 от Harlon » Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3947



Просмотр профиля
« Ответ #14 : Июнь 06, 2018, 21:15 »

Вы вычитываете из сокета массив, а потом делаете readAll? Вычитаваете остальные пришедшие данные и теряете их?
Записан
Страниц: [1] 2 3   Вверх
  Печать  
 
Перейти в:  

Страница сгенерирована за 0.176 секунд. Запросов: 22.