Форум программистов, компьютерный форум, киберфорум
C++ Qt
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.65/26: Рейтинг темы: голосов - 26, средняя оценка - 4.65
 Аватар для android52
1 / 1 / 0
Регистрация: 25.04.2015
Сообщений: 26

Потоки, QSeriaport, QTcpserver (Алгоритм чтения/отправки данных)

08.03.2016, 14:31. Показов 6089. Ответов 66
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте, уважаемые жители кибер форума. Обращаюсь за консультацией.

Вопрос в следующем. Есть устройство на чипе PIC18F2550, которые шлет пакеты по COM порту. (длина пакетов 10-30 байт, максимально возможное кол-во пакетов в секунду 300-500).

Пишу софт, для работы с данным устройством. Требования к функционалу следующие:
Читать данные с устройства, записать эти данные в файл и отправить эти данные ко всем, кто подключен к сокету, если никого на сокете нет - не отправлять.

Есть сигнал (ReadyRead), т.е. как только устройство готово что-то передать, вызывается некоторый слот, в котором данные считываются функцией ReadLine() или ReadAll(). Далее, в этой функции: если в GUI чекбокс нажат, происходит вызов функции writeBin, в качестве аргумента ей передается полученный с устройства QByteArray (происходит запись полученных данных в файл). По моей идее необходимо сделать еще одну функцию (Функция отправки по сети), которой в качестве аргумента передается тот же массив полученных с устройства QByteArray.

Теперь вопросы. Как сделать алгоритм чтения/записи/отправки так, чтобы не пострадал прием данных с устройства. И вообще как ведут себя сигналы в данном случае? Т.е. получил сигнал ReadyRead о том, что ожидают чтения с устройства байты, начинается выполняться слот по чтению данных. И тут подключатся клиент (вызывается сигнал NewConnection). Управление с функции readyRead передается слоту, который срабатывает при сигнале NewConnection. Соответственно чтение с устройства прерываются до тех пор, пока не отработает newconnection либо пока не придет новый сигнал ReadyRead. Это вопрос номер 1.

И вопрос номер 2. Например все хорошо, и у нас 2 клиента. Если писать процедурно, то для отправки двум клиентам функция будет вызываться 2 раза. Ну или один раз (зациклить по кол-во соединенных сокетов). Так вот в чем беда, с приемника данные продолжают сыпаться. И пока функция не отправит предыдущие данные, чтение новых не происходит чтоли?

На правильность идеи не претендую. Любая критика приветствуется.
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
08.03.2016, 14:31
Ответы с готовыми решениями:

Алгоритм чтения данных из памяти
Привет. Не могу придумать алгоритм чтения данных из памяти. В общем, данные (данные - это массив char размером 64 байта) пишутся в...

Алгоритм чтения текстового файла в массив данных открытого типа
Помогите написать алгоритм чтения текстового файла в массив данных открытого типа

Потоки чтения и записи.
Здравствуйте, помогите пожалуйста разобраться с потоками чтения и записи информации. Проблема такова. Программа должна создать поток...

66
68 / 68 / 17
Регистрация: 20.01.2015
Сообщений: 347
11.04.2016, 22:16
Студворк — интернет-сервис помощи студентам
socket->deleteLater();
0
 Аватар для android52
1 / 1 / 0
Регистрация: 25.04.2015
Сообщений: 26
11.04.2016, 23:26  [ТС]
Amok, немного неправильно вопрос поставил. Ошибка возникает при отправке данных. Т.е. пришел юзер, записался в карту его дескриптор, вызывается функция отправки данных, которая всю карту перебирает (всех пользователей) и всем отсылает данные. В тот момент, когда пользователь отключается и вызывается слот disconnect я пытаюсь удалить его из карты (но в этот же момент происходит перебор этой же карты и отправка данных другим клиентам). В итоге клиент отключается и появляется вышеуказанная ошибка. Вроде как проблема с приоритетами, доступ к данным из разных потоков (пытается удалить данные из карты, которая в этот момент находится в работе). Других мыслей у меня по этому поводу нет. Ниже исходные данные:
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
void MainWindow::slotNewConnection()
{
    writeLogsDisplay("\nNew client");
    QTcpSocket* socket = server->nextPendingConnection();
    int id = socket->socketDescriptor();
    clients[id]= socket;  -----------------------------> добавляю в карту вновь подключившегося
    connect(this, SIGNAL(writeData(QString)), this, SLOT(slotWrite(QString)));
    connect(clients[id], SIGNAL(disconnected()), this, SLOT(slotDisconnected()));
}
 
void MainWindow::slotWrite(QString msg)
{
        foreach(int i,clients.keys()){ -----------------------------> отправляю всем, кто есть в карте
        QByteArray arrBlock;
        QDataStream out(&arrBlock, QIODevice::WriteOnly);
        out << quint16(0) << msg;
        out.device()->seek(0);
        out << quint16(arrBlock.size() - sizeof(quint16));
        clients[i]->write(arrBlock);
    }
}
 
void MainWindow::slotDisconnected()
{
    writeLogsDisplay("\nClient disconnected");
    QTcpSocket* socket = (QTcpSocket*)sender();
    int id = socket->socketDescriptor();
    clients.remove(id);   -----------------------------> удаляю из карты отключившегося
    socket->close();
}
Ошибка
C++ (Qt)
1
QIODevice::write (QTcpSocket): device not open
0
68 / 68 / 17
Регистрация: 20.01.2015
Сообщений: 347
12.04.2016, 00:49
У тебя все в одном классе MainWindow? У него одна очередь сообщений. соответственно пока не выполнится отправка, не произойдет дисконнект т.к. дисконнект поставится в очередь. Но, тем не менее, это не помешает отключится пользователю на том конце в момент отправки. Как результат, если пользователь отключается в момент рассылки, id клиента еще не удален и будет попытка отправить ему сообщение. Возможно в процессе отправки следующему клиенту стоит проверять пришло ли событие дисконнекта? И если пришло, обрабатывать его, но если портов много это может замедлить процесс..
1
44 / 44 / 12
Регистрация: 05.04.2015
Сообщений: 345
12.04.2016, 17:00
QMap хранит указатели или объекты?
0
Эксперт С++
 Аватар для Avazart
8489 / 6156 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
12.04.2016, 20:05
Цитата Сообщение от Amok Посмотреть сообщение
Докума Qt говорит о том, что переопределять класс QThread для внесения в него пользовательских данных не комильфо.
Где именно? proof? Вообще то в доке существуют оба примера использования QThread.
Самое важно какие последствия возникают и как правильно применять тот или иной подход.
0
 Аватар для android52
1 / 1 / 0
Регистрация: 25.04.2015
Сообщений: 26
12.04.2016, 20:06  [ТС]
kolts, я так понимаю объекты сокетов
0
Эксперт С++
 Аватар для Avazart
8489 / 6156 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
12.04.2016, 20:18
Цитата Сообщение от icpu Посмотреть сообщение
Запихивать их в отдельный поток - глупо и имеет смысл только в составе глобального разнесения функционала на потоки. Ну, к примеру, по потоку на робота, но и то, если не хватает стандартной производительности.
Глупое утверждение, ибо намного чаще нужно еще и обрабатывать данные и принимать решения.
Цитата Сообщение от icpu Посмотреть сообщение
Потому ваш труд - труд Сизифов. Даже если обработка получаемых данных производится в отличном от основного потоке, достаточно просто соединить их сигналослотами - и всё.
- Вот это действительно глупая идея. Попробуйте реализовать и убедитесь в этом.
Более того иногда это просто неудобно.
0
 Аватар для android52
1 / 1 / 0
Регистрация: 25.04.2015
Сообщений: 26
12.04.2016, 20:34  [ТС]
Покурил доку, состояние сокета. И решил сделать проверку в слоте write на статус сокета.

C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
void MainWindow::slotWrite(QString msg)
{
    foreach(int i,clients.keys()){  -------------------> отправляю всем, кто находится в карте
        if(clients[i] == QTcpSocket::ConnectedState){  ------> проверяю сокет на подключение 
        QByteArray arrBlock;
        QDataStream out(&arrBlock, QIODevice::WriteOnly);
        out << quint16(0) << msg;
        out.device()->seek(0);
        out << quint16(arrBlock.size() - sizeof(quint16));
        clients[i]->write(arrBlock);
        }
        else {
            clients[i]->close(); -------> закрываю сокет, если не подключен
            clients.remove(i); -------> удаляю его из карты
        }
    }
}
 
void MainWindow::slotDisconnected()
{
    writeLogsDisplay("\nClient disconnected");
    QTcpSocket* socket = (QTcpSocket*)sender();
    int id = socket->socketDescriptor();
    clients.remove(id);   -----------------------------> удаляю из карты отключившегося
    socket->close();
}
Разумно ли? Теперь стоит вопрос, зачем слот дисконнект теперь нужен. Если при отправке данных ненужные объекты закрываются и удаляются
И наверное, необходимо сделать проверку, пустая ли карта. Т.к. слот write срабатывает при получении данных с компорта.
0
Эксперт С++
 Аватар для Avazart
8489 / 6156 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
12.04.2016, 20:50
Цитата Сообщение от android52 Посмотреть сообщение
Покурил доку, состояние сокета. И решил сделать проверку в слоте write на статус сокета.
"Состояние" можно определить только при попытке записи/чтения в/из сокета, т.е при возникновении ошибок сети либо отсутствие таковых.
Попытка проверить перед записью:
C++ (Qt)
1
if(clients[i] == QTcpSocket::ConnectedState)
Ничего не даст.

Более того то что вы делаете итерацию по такому контейнеру и выполняете там же удаление из контейнера может приводить к ошибкам.
0
 Аватар для android52
1 / 1 / 0
Регистрация: 25.04.2015
Сообщений: 26
12.04.2016, 20:59  [ТС]
Avazart
C++ (Qt)
1
if(clients[i]->state() == QTcpSocket::ConnectedState)
0
Эксперт С++
 Аватар для Avazart
8489 / 6156 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
12.04.2016, 21:05
И что?
C++
1
clients[i]->state()
Ничего не знает о том в каком состоянии "сеть" вы можете выдернуть кабель с подключением к интернету
а clients[i]->state() вам будет показывать что сокет подключен, и только при попытке записи или чтения в/из сокет
вы получите ошибку говорящую что что-то не так.
[I] (и возможно только после этого clients->state() будет сброшен, но это зависит от реализации может и не сбрасываться)
1
 Аватар для android52
1 / 1 / 0
Регистрация: 25.04.2015
Сообщений: 26
12.04.2016, 21:07  [ТС]
Avazart, как тогда при дисконнекте удалить объект из карты?
0
Эксперт С++
 Аватар для Avazart
8489 / 6156 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
12.04.2016, 21:08
Цитата Сообщение от android52 Посмотреть сообщение
Avazart, как тогда при дисконнекте удалить объект из карты?
А подумать?
1
 Аватар для android52
1 / 1 / 0
Регистрация: 25.04.2015
Сообщений: 26
12.04.2016, 23:01  [ТС]
Avazart, нашел в документации...
C++ (Qt)
1
2
3
4
5
При входе в цикл foreach, Qt автоматически делает копию контейнера. 
Если вы измените контейнер во время выполнения цикла, то в цикле этого не будет заметно.
(Если вы не изменяли контейнер, копирование все еще имеет место, но, 
благодаря неявному совместному использованию данных, 
копирование контейнера осуществляется очень быстро.)
0
 Аватар для icpu
487 / 365 / 93
Регистрация: 10.03.2011
Сообщений: 1,513
Записей в блоге: 5
13.04.2016, 08:57
Цитата Сообщение от Avazart Посмотреть сообщение
Глупое утверждение, ибо намного чаще нужно еще и обрабатывать данные и принимать решения.
В общем случае, да. В конкретных - нет. Зависит от объёма вычислений и числа ядер. Наплодить 100500 потоков тоже не самая лучшая идея - переключение между контекстами достаточно дорого стоит.
Цитата Сообщение от Avazart Посмотреть сообщение
- Вот это действительно глупая идея. Попробуйте реализовать и убедитесь в этом.
Более того иногда это просто неудобно.
А иногда до жути удобно. Здесь мил человек нагородил обход в цикле всех сокетов и пересылку всем одинаковых данных, хотя куда логичнее было бы подцепить их всех на один единственный сигнал.
C++ (Qt)
1
2
connect (this, SIGNAL(signalWrite(QByteArray)),clients[i],SLOT(write(QByteArray)));
emit signalWrite(arrBlock); //broadcast
Следующий шаг - добавление ID в сигналы и слоты и определение -1 для бродкаста. Потом появятся сигналмапперы. А там и до ожидающих и блокирующих соединений на удаление не далеко
C++ (Qt)
1
2
3
4
5
6
7
8
9
connect(clients[id], SIGNAL(disconnected()), this, SLOT(slotDisconnected()),Qt::QueuedConnection);
void MainWindow::slotDisconnected()
{
    writeLogsDisplay("\nClient disconnected");
    QTcpSocket* socket = (QTcpSocket*)sender();
    int id = socket->socketDescriptor();
    socket->close();
    clients.takeAt(id)->deleteLater();
}
Ещё немного, и можно будет делать MainWindow родителем всех сокетов, а потом отойти от массива сокетов до массива идешек.
Скажите мне, что обход QList<int> намного сложнее обхода QHash<int,QTcpSocket*> или что максимальный фейл в первом случае - сообщение вникуда - хуже, чем все те статик ассёрты и прочее прочее во втором. Где тут неудобство?

Добавлено через 5 минут
Хотя понятно, что если клиент - чуть больше, чем слушатель радио, для него нужно создавать отдельный класс и вытеснять всю логику в него. Со временем android52 придёт и к этому, а пока пусть пытается делать так, как у него всё равно работать не будет.
0
Эксперт С++
 Аватар для Avazart
8489 / 6156 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
13.04.2016, 15:49
Цитата Сообщение от android52 Посмотреть сообщение
Avazart, нашел в документации...
Ну да, с контейнерами Qt это проканает, пускай и с ненужным копированием, а вот с STL нет.
0
68 / 68 / 17
Регистрация: 20.01.2015
Сообщений: 347
13.04.2016, 19:30
Avazart, «QThread was designed and is intended to be used as an interface or a control point to an operating system thread, not as a place to put code that you want to run in a thread. We object-oriented programmers subclass because we want to extend or specialize the base class functionality. The only valid reasons I can think of for subclassing QThread is to add functionality that QThread doesn’t have, e.g. perhaps providing a pointer to memory to use as the thread’s stack, or possibly adding real-time interfaces/support. Code to download a file, or to query a database, or to do any other kind of processing should not be added to a subclass of QThread; it should be encapsulated in an object of it’s own.»

Ноги: https://habrahabr.ru/post/150274/
0
Эксперт С++
 Аватар для Avazart
8489 / 6156 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
13.04.2016, 19:55
Ссылку на официальную доку пожалуйста, ибо в http://doc.qt.io/qt-5/qthread.html я чет такого не вижу, зато вижу примеры для каждого подхода.

Добавлено через 2 минуты
Цитата Сообщение от Amok Посмотреть сообщение
Ноги вижу, откуда руки?
0
68 / 68 / 17
Регистрация: 20.01.2015
Сообщений: 347
13.04.2016, 20:04
Avazart, слов разработчика вам будет вполне достаточно. Примеры в доке вовсе не отменяют целей применения того или иного метода, но в доке, само собой, они должны быть описаны оба.

Добавлено через 7 минут
Про руки актуально спросить вот здесь:
https://blog.qt.io/blog/author/brad/
0
Эксперт С++
 Аватар для Avazart
8489 / 6156 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
13.04.2016, 20:08
Цитата Сообщение от Amok Посмотреть сообщение
Avazart, слов разработчика вам будет вполне достаточно.
А если нет?

Если есть оба подхода и оба работоспособны, значит говорить что один правильный, а другой нет- глупо.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
13.04.2016, 20:08

Потоки С++.Файл не открывает себя для чтения.
B]Добрый день уважаемые участники форума. Мне была поставлена задача создать две программы: 1) Первая программа Write_Info.ехе...

Алгоритм отправки формы
Как устроен алгоритм отправки формы и дальнейшего использования данных, т.е. отправили форму, куда она приходит и кем обрабатывается?

Алгоритм чтения файла
Доброго времени суток! Есть задача: Вывести в консоль значения строк, которые стоят под #, ##, ###. Вот пример txt-файла: ...

Алгоритм отправки файла на почту
Как осуществить оправку текстового файла допустим на 777@mail.ru Буду благадарен любой информации особенно исходникам :-)

Алгоритм получения и отправки reCaptcha
Всем привет. Скажу заранее, рабочего и точного алгоритма действий я не нашел ни на форумах, ни в гугле. Мне интересен алгоритм...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
Новые блоги и статьи
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр.
Jin X 06.09.2026
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр. Работая с форумом и нейросетями в браузере часто хочется что-то подкорректировать или добавить какого-то функционала. Ниже прикреплён. . .
Программа опроса у.з. расходомера SLS-720F
Argus19 02.09.2026
Программа опроса у. з. расходомера SLS-720F Программа опрашивает один раз в минуту три ультразвуковых расходомера SLS-720F через интерфейс RS-485 по протоколу Modbus RTU. Опрашиваются регистры. . .
Hyper-V: Компьютер должен поддерживать доверенный платформенный модуль 2.0.
Maks 31.08.2026
При установке Windows 11 на виртуальную машину Hyper-V 2-го поколения вылезла такая ошибка: Решение: в параметрах виртуальной машины, в разделе "Безопасность" (Security) активировать флаг. . .
Архитектура биовида Стива в Майнкрафте: Зачем бонобо кубический каннибализм
anaschu 30.08.2026
Кубический Вагинокапитализм в Minecraft: Математический инвариант ОДУ и рок Стивов-бонобо Главная задача разработанной «Модели Всего» — наглядно продемонстрировать наличие системной «судьбы». . .
Оттачиваю умение писать js программы.
russiannick 30.08.2026
Проектом выходного дня стало написание Книги шифров Виженера. Итогом стала версия 200, синий туман. Синий туман назван так, потому что замораживает текст под собой. Нажатие синих кнопок управляют. . .
мат медиц модель 30. презентация проекта
anaschu 27.08.2026
хоп хоп хоп хидахоп, а я кладую))
Как у меня протекала болезнь
zorxor 27.08.2026
Здравствуйте, друзья! Эта запись блога предназначена именно для вас - для моих дорогих друзей, которые знали меня лично. Чтобы ответить на вопрос - а что же со мной произошло на самом деле? Я учился. . .
Нашел вот забавное видео о измерениях. Лучшее что я видел на эту тему
kumehtar 26.08.2026
ILETXiw9bMQ Основная суть и тезисы по измерениям: 0D (Нулевое измерение): точка, не имеющая длины, ширины, высоты или объема. Объект не может перемещаться в 0D. 1D (Первое измерение):. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru