Как правильно читать данные с многопоточным сервером? |
Здравствуйте, гость ( Вход | Регистрация )
Как правильно читать данные с многопоточным сервером? |
Andrewshkovskii |
15.5.2010, 18:50
Сообщение
#1
|
Активный участник Группа: Участник Сообщений: 351 Регистрация: 27.12.2008 Пользователь №: 467 Спасибо сказали: 18 раз(а) Репутация: 1 |
Есть клиент (наслденик QTcpSocket) , в нем реализованы функции запроса к серверу :
Сервер от QTcpServer :
И клиентский поток от QThread :
Первый раз пишу клиент/сервер. Но почему-то у меня не запускается поток, т.е. получается что сокет не генирирует сигнал readyRead? А почему, ведь данные приходят от клиента..нет ? Сообщение отредактировал Andrewshkovskii - 15.5.2010, 19:34 |
|
|
kibsoft |
15.5.2010, 19:12
Сообщение
#2
|
Участник Группа: Участник Сообщений: 180 Регистрация: 21.7.2009 Из: Самара Пользователь №: 928 Спасибо сказали: 14 раз(а) Репутация: 2 |
Threaded Fortune Server Example посмотри его в ассистенте.. Там понятно написано как делать. У тебя немного неправильный подход.
Такое не будет работать. Создавать socket лучше в run(). И при этом создать какой-нибудь отдельный объект в том же run(), слот у которого будет обрабатывать readyRead(). Создавать объект нужно для того, чтобы socket и данный объект были созданы в одинаковом потоке. Почитайте о потоках подробнее в документации.
|
|
|
Andrewshkovskii |
15.5.2010, 19:21
Сообщение
#3
|
Активный участник Группа: Участник Сообщений: 351 Регистрация: 27.12.2008 Пользователь №: 467 Спасибо сказали: 18 раз(а) Репутация: 1 |
Т.е. что бы обработать readyRead в потоке (проще говоря - считать данные с сокета) необходимо создать этот сокет во время работы потока + что бы данные считывались не самим экземпляром потока, а неким объектом по сигналу readyRead от сокета??
================ А если соеденить readyRead сокета с слотом потока?Тоже не будет взаимодействовать, как я понимаю? Сообщение отредактировал Andrewshkovskii - 15.5.2010, 19:39 |
|
|
kibsoft |
15.5.2010, 19:45
Сообщение
#4
|
Участник Группа: Участник Сообщений: 180 Регистрация: 21.7.2009 Из: Самара Пользователь №: 928 Спасибо сказали: 14 раз(а) Репутация: 2 |
Т.е. что бы обработать readyRead в потоке (проще говоря - считать данные с сокета) необходимо создать этот сокет во время работы потока + что бы данные считывались не самим экземпляром потока, а неким объектом по сигналу readyRead от сокета?? Да, т.к. экземпляр потока создан в другом потоке, поэтому нельзя делать connect с DirectConnection, т.е. чтобы слот вызывался сразу после испускания сиглнала. По-моему можно QueuedConnection, но я не пробовал так. Signals and Slots Across Threads - тут в ассистенте описание. P.S. Qt::QueuedConnection - при генерации сигнал помещается в очередь обработки событий. |
|
|
Andrewshkovskii |
16.5.2010, 15:04
Сообщение
#5
|
Активный участник Группа: Участник Сообщений: 351 Регистрация: 27.12.2008 Пользователь №: 467 Спасибо сказали: 18 раз(а) Репутация: 1 |
Я попробовал сделать вот так :
Крашит с таким сообщением : Цитата reading client before crash QObject: Cannot create children for a parent that is in a different thread. (Parent is QNativeSocketEngine(0x9909e80), parent's thread is ClientThread(0x98f a6b0), current thread is QThread(0x3e4970) Т.е. получается я не могу записать в сокет, находясь в другом методе. НО сообщение гласит о том, что я не могу создать потомка для родителя из другого треда.Но я и не пытаюсь создать... |
|
|
kibsoft |
16.5.2010, 15:45
Сообщение
#6
|
Участник Группа: Участник Сообщений: 180 Регистрация: 21.7.2009 Из: Самара Пользователь №: 928 Спасибо сказали: 14 раз(а) Репутация: 2 |
socket->write(block); нельзя использовать объекты из разных потоков. Т.е. void ClientThread::readClientSocket() создан и выполняется в основном потоке, а т.к. socket создан в потоке ClientThread, то использовать в другом потоке его нельзя. Соответственно, можно сделать как я предлагал(отдельный объект), либо наследовать сам qtcpsocket и определить в нем слот записи (this->write...). И вместо socket->write(block); в readClientSocket() высылать сигнал на слот записи.
|
|
|
Andrewshkovskii |
16.5.2010, 16:09
Сообщение
#7
|
Активный участник Группа: Участник Сообщений: 351 Регистрация: 27.12.2008 Пользователь №: 467 Спасибо сказали: 18 раз(а) Репутация: 1 |
Мне передать указатель на сокет в этот объект, или же просто определить слот в котором буду писать в сокет ?
А нельзя ли сокет "передвинуть" ( moveToThread() ) в clientThread поток? Сделал объект :
И код run() :
В консоль приходит только : reading client, данные с сокета почему-то не считываются.. Сделал небольшую отладку.. в requestType находиться 0..получается данные куда-то делись, либо я не правильно их читаю. Записываю вот так :
Сообщение отредактировал Andrewshkovskii - 16.5.2010, 17:06 |
|
|
kibsoft |
16.5.2010, 18:21
Сообщение
#8
|
Участник Группа: Участник Сообщений: 180 Регистрация: 21.7.2009 Из: Самара Пользователь №: 928 Спасибо сказали: 14 раз(а) Репутация: 2 |
Цитата А нельзя ли сокет "передвинуть" ( moveToThread() ) в clientThread поток? 1) Socket и находиться в потоке clientThread(т.к. он определен в этом классе). А сам clientThread находиться в основном потоке. Т.е. есть основной поток, который создал clientThread(новый поток). 2) if( socket->bytesAvailable() < nextBlockSize) { return; } Косяк у тебя с первого взгляда здесь. Т.е. когда не все данные пришли ты выходишь из слота, но в следующий раз у тебя слот опять будет читать размер пакета и следовательно все нарушится(читать будет не те данные). Ну и естественно в requestType у тебя случайные данные.. Поэтому лучше сделай цикл бесконечный. В Шлее книге есть пример принятия. |
|
|
Andrewshkovskii |
16.5.2010, 21:51
Сообщение
#9
|
Активный участник Группа: Участник Сообщений: 351 Регистрация: 27.12.2008 Пользователь №: 467 Спасибо сказали: 18 раз(а) Репутация: 1 |
Ну с forever на получение полных данных я понял.но у меня другая проблема. Что бы запустить цикл обработки событий в функции run() потока я использую
exec() :
Если не запускать - брокер не поймает сигнал , и ничего не произойдет. И вот ещё насчет брокера запросов.. :
Я получаю на такие данные
вот такой отладочный вывод : Цитата reading client true 7 total bytes 344832 before read request is : И поток не завершается без exit() , т.е. поток остается в незавершенном режиме и не удаляется. Из брокера я не могу вызвать ни exec() ни exit, разве что явно указать parent'a ему, и через указатель на родителя вызывать. Но основная проблема в том, что я не могу никак написать код, который бы читал/принимал данные корректно. |
|
|
kibsoft |
17.5.2010, 12:15
Сообщение
#10
|
Участник Группа: Участник Сообщений: 180 Регистрация: 21.7.2009 Из: Самара Пользователь №: 928 Спасибо сказали: 14 раз(а) Репутация: 2 |
после exec() уже ничего никогда не выполниться. тут return надо.exit можно связать с сигналом disconnected сокета, а при создании объекта ClientThread в сервере - указать deleteLayer, чтобы объект удалялся при выходе из цикла событий. |
|
|
Текстовая версия | Сейчас: 21.12.2024, 17:30 |