Название: Передача сокета в другой поток Отправлено: qtkoder777 от Апрель 20, 2016, 17:53 Здравствуйте.
Возникла задача написать такой сервер: Сервер должен получить данные от клиентов, провести над ними некоторые вычисления и вернуть результат клиенту. В процессе вычислений могут поступать новые запросы. Пытаюсь сделать так: Ввёл структуру, в которой запоминаю сокет клиента, которому надо отослать результат работы с data_. Код и очередь QQueue этих структур, которая заполняется в основном потоке Вычисления крутятся в отдельном потоке наследнике QThread. Данные извлекаются из очереди, обрабатываются, и отправляются клиенту с помощью Код , если очередь пуста, крутится бесконечный цикл. Фактически, из потока вычислений данные НЕ ДОХОДЯТ до клиента, хотя write завершается без ошибки. В основном потоке данные по тому же сокету отправляются и доходят. Читал где то на другом форуме, что сокеты нельзя передавать между потоками. Так ли это? И как надо поступать? Название: Re: Передача сокета в другой поток Отправлено: Old от Апрель 21, 2016, 07:47 В рабочих нитках можно только обрабатывать, а результат возвращать в нить сетевого обмена, из которой и отправлять ее клиенту.
Название: Re: Передача сокета в другой поток Отправлено: qtkoder777 от Апрель 21, 2016, 11:18 Откуда сокет вообще знает в какой он нитке - это особенность Qt?
Подходит ли вообще Qt для написания таких программ? Может стоит смотреть в сторону других библиотек, раз в Qt такие сложности. Название: Re: Передача сокета в другой поток Отправлено: Old от Апрель 21, 2016, 11:24 Откуда сокет вообще знает в какой он нитке - это особенность Qt? Для того, что бы обеспечить правильную работу сигналов в многопоточных программах, в Qt введено понятие контекст потока.Изменяется он с помощью метода: QObject::moveToThread. Подходит ли вообще Qt для написания таких программ? Скажем так, такие программы на Qt можно писать. Насколько это будет эффективно вопрос другой.Может стоит смотреть в сторону других библиотек, раз в Qt такие сложности. Я лично использую для этого boost::asio. Название: Re: Передача сокета в другой поток Отправлено: qtkoder777 от Апрель 23, 2016, 16:37 В рабочих нитках можно только обрабатывать, а результат возвращать в нить сетевого обмена, из которой и отправлять ее клиенту. А как вернуть результат в нить сетевого обмена?Название: Re: Передача сокета в другой поток Отправлено: Old от Апрель 23, 2016, 16:59 А как вернуть результат в нить сетевого обмена? Например, можно возвращать готовый для отбравки объект QByteArray.Название: Re: Передача сокета в другой поток Отправлено: qtkoder777 от Апрель 23, 2016, 17:32 А как вернуть результат в нить сетевого обмена? Например, можно возвращать готовый для отбравки объект QByteArray.Название: Re: Передача сокета в другой поток Отправлено: Old от Апрель 23, 2016, 17:58 Сигнал-слот? Как вариант. :)Название: Re: Передача сокета в другой поток Отправлено: sergek от Апрель 23, 2016, 18:00 А это не единственно правильный вариант? :)
Название: Re: Передача сокета в другой поток Отправлено: Old от Апрель 23, 2016, 18:08 А это не единственно правильный вариант? :) Конечно нет. Для передачи результатов, так же как и для передачи заданий, можно использовать самописные очереди, мэилбоксы и другие механизмы межпоточных взаимодействий.Название: Re: Передача сокета в другой поток Отправлено: qtkoder777 от Апрель 23, 2016, 18:41 Как следует поступать когда потоку "нечего делать"?
Крутиться в бесконечном цикле и проверять, не появилось ли чего в очереди - это правильно или нет? Название: Re: Передача сокета в другой поток Отправлено: Old от Апрель 23, 2016, 18:46 В идеале он должен спать и просыпаться только когда появилась работа. Поищите по форуму, было несколько тем с примерами про очереди и QWaitCondition.
Название: Re: Передача сокета в другой поток Отправлено: qtkoder777 от Апрель 23, 2016, 19:02 Какие параметры должен иметь сигнал для передачи результатов?
Сигнал получат все потоки соединений, надо как-то узнать какому потоку предназначен сигнал. То есть два параметра - строка результата и this потока? Название: Re: Передача сокета в другой поток Отправлено: Old от Апрель 23, 2016, 19:16 В самом простом случае с Qt-сигналами: сетевая нитка должна передать рабочей какой-то идентификатор клиента/сокета, от которого получен этот запрос и исходные данные для работы. После завершения обработки рабочая нитка должна передать сетевой тот же идентификатор клиента/сокета и результат работы. Сетевая нитка по идентификатору находит нужный сокет и отправляет в результат.
Название: Re: Передача сокета в другой поток Отправлено: qtkoder777 от Апрель 23, 2016, 19:17 Какие особенности у межпоточного connect-a?
Обнаружилось, что после такого connect-a сокет, который в нити thread, перестаёт получать данные (ft - нить вычислений) Код
Код Есть какой-то загадочный последний необязательный параметр, может там чего надо прописать? Название: Re: Передача сокета в другой поток Отправлено: Old от Апрель 23, 2016, 19:23 Рекомендую вам сначало разобраться с работой сигналов между нитками, а только потом добавлять туда сеть. На форуме много это обсуждалось, есть масса статей интернете. Там есть несколько тонкостей.
Название: Re: Передача сокета в другой поток Отправлено: qtkoder777 от Апрель 23, 2016, 19:33 Рекомендую вам сначало разобраться с работой сигналов между нитками, а только потом добавлять туда сеть. На форуме много это обсуждалось, есть масса статей интернете. Там есть несколько тонкостей. А можете дать ссылку на какую нибудь хорошую статью?Статей то много, но непонятно чему верить а чему нет. Нет времени всё перепробовать. Что-то такое пишут - это правильный способ? Код Может есть в сети готовые исходники сервера с обработкой заданий? А на boost это легче написать? С boost совсем не знаком. Название: Re: Передача сокета в другой поток Отправлено: Old от Апрель 23, 2016, 20:09 А можете дать ссылку на какую нибудь хорошую статью? К сожалению ссылок не знаю. Основные моменты там в том, что если инициатор сигнала расположен в другом потоке от получателя, то слот вызывается не в момент испускания сигнала, а через очередь сообщений потока-получателя. Т.е. для работы этого механизма, в потоке-получателе должен крутиться цикл обработки событий. Все аргументы сигнала сохраняются в событии и слот вызывается с копиями этих аргументов. Последний параметр connect как раз отвечает за тип подключения.Что-то такое пишут - это правильный способ? Это рабочий способ.А на boost это легче написать? Легче, если умеете на нем. Если не знакомы, то с Qt будет проще.С boost совсем не знаком. Название: Re: Передача сокета в другой поток Отправлено: qtkoder777 от Апрель 23, 2016, 20:46 Я поставил последний параметр Qt::QueuedConnection и это не помогло.
Написано что по умолчанию Qt сам определяет один поток или разные. Почему сокет не принимает данные если сделать connect? Название: Re: Передача сокета в другой поток Отправлено: Old от Апрель 23, 2016, 20:56 Я поставил последний параметр Qt::QueuedConnection и это не помогло. Метод научного тыка здесь вряд-ли поможет. Вначале разберитесь просто с сигналами, что бы один поток посылал сигнал, а во втором срабатывал слот. Погоняйте туда-сюда данные.Написано что по умолчанию Qt сам определяет один поток или разные. Сокет не принимает данные. А уже потом добавляйте сеть. Я уже писал, но повторю: для работы с клиентами достаточно одного потока, в котором и будут работать все сокеты, а вот для обработки можно использовать пул рабочих потоков. Название: Re: Передача сокета в другой поток Отправлено: qtkoder777 от Апрель 23, 2016, 21:02 Метод научного тыка здесь вряд-ли поможет. Вначале разберитесь просто с сигналами, что бы один поток посылал сигнал, а во втором срабатывал слот. Где-то пишут что надо использовать moveToThread. А без этого можно? Название: Re: Передача сокета в другой поток Отправлено: Old от Апрель 23, 2016, 21:09 По каким материалам разбираться? Вот вы что читали? Документацию + смотрел исходники Qt. Но я Qt начал использовать году в 2000, так что все эти "нововведения" с межпоточными сигналами появлялись на моих глазах. :)Где-то пишут что надо использовать moveToThread. А без этого можно? С помощью этого метода вы указываете в контексте какой нитки будет существовать объект. Это важно для правильного определения типа коннекта: если объект инициатор и объект получатель в разных потоках, то будет использоваться вызов слота получателя через его очередь сообщений.Название: Re: Передача сокета в другой поток Отправлено: qtkoder777 от Апрель 23, 2016, 21:21 Нужна волшебная строчка, которая законнектит сигнал из одного потока на слот в другом потоке.
Почему нельзя её написать? Или это страница кода, а не строчка? Потоки делаю как наследники от QThread согласно документации на Qt. Хотя кое-где пишут что это неправильно. Вот эта статья более не менее рабочая? https://habrahabr.ru/post/150274/ Название: Re: Передача сокета в другой поток Отправлено: Old от Апрель 23, 2016, 21:28 Нужна волшебная строчка, которая законнектит сигнал из одного потока на слот в другом потоке. Нет никаких волшебных строчек. Для демонстрации нужно написать два класса, я сейчас пишу с телефона, у меня нет возможности набирать код.Почему нельзя её написать? Или это страница кода, а не строчка? Потоки делаю как наследники от QThread согласно документации на Qt. Хотя кое-где пишут что это неправильно. Я бы не затевался с QThread, я бы взял QtConcurrent для выполнения функций в отдельных потоках + QFutureWatcher для определения завершения расчета и получения результата. Посмотрите на QtConcurrent, это высокоуровневая надстройка над пулом потоков. QFuture<T> QtConcurrent::run(Function function, ... ) Название: Re: Передача сокета в другой поток Отправлено: qtkoder777 от Апрель 23, 2016, 22:49 А сервер не обязан быть многопоточным - на каждого клиента свой поток?
Название: Re: Передача сокета в другой поток Отправлено: Old от Апрель 24, 2016, 06:26 А сервер не обязан быть многопоточным - на каждого клиента свой поток? Конечно не обязан, более того такой сервер не жизнеспособен, когда должен обслуживать тысячи клиентов одновременно.Название: Re: Передача сокета в другой поток Отправлено: Igors от Апрель 24, 2016, 07:52 Что-то такое пишут - это правильный способ? Да. Хотя наследование от QThread будет работать с тем же успехом - создание worker'а более идейно/концептуально, в общем "рекомендуют".Почему сокет не принимает данные если сделать connect? Сокет-сокет.. Вы сначала убедитесь что сконнектились верно, т.е. сигнал испущенный из одной нитки принимается в другой. Для этого надо сделать moveToThread как в примере (или moveToThread(this) если наследуетесь от QThread). Для проверки поставьте печать (напр qDebug() << QThread::currentThread()) тут и там. |