Название: Клиент-сервер(мультитрит): передача открытого сокета из одного Thread в другой Отправлено: bvn13 от Января 31, 2010, 23:01 пишу многопоточное клиент-серверное приложение.
заткнулся на какой-то банальщине... Сервер: Код: void MYthread::run() идея: при новом коннекте (slot_onNewConnection()) должен создаваться MYclientThread(public QThread), ему передаваться сокет, а он уже с этим сокетом обмениваться данными... но ни вариант 1, ни вариант 2 не работает. вернее... вот прием сокета в классе MYclientThread: Код: MYclientThread::MYclientThread(int desc, QObject *parent) //конструктор сообщения появляются в следующей очереди: 1) MYclientThread running 2) MYclientThread Something is wrong! - Disconnecting.. 3) MYclientThread Something is wrong! - Disconnecting.. //почему второй раз??? подскажите мне, пожалуйста, что я делаю не так? почему обваливается сокет? и как правильнее передать сокет от одного потока другому? Название: Re: Клиент-сервер(мультитрит): передача открытого сокета из одного Thread в другой Отправлено: niXman от Января 31, 2010, 23:13 все не так. пиши с нуля.
псевдокод: Код
Название: Re: Клиент-сервер(мультитрит): передача открытого сокета из одного Thread в другой Отправлено: bvn13 от Января 31, 2010, 23:19 ок, спасибо. перепишу.
ЗЫ! начал сейчас ставить мессаги по ходу приема-передачи данных на сервере и обнаружил, что валит прием данных! вот код, который я стягивал с какого-то примера (то ли это threadedFortuneServer, то ли еще какой - не помню): Код: int MYclientThread::recieveFromClient_string(QString *result) от безысходности в понимании сего примера хочу спросить: как правильно считывать/записасывать данные из/в сокет(а)? да, перед вызовом этого кода надо ставить waitForReadyRead() ? Название: Re: Клиент-сервер(мультитрит): передача открытого сокета из одного Thread в другой Отправлено: BRE от Января 31, 2010, 23:21 Желательно сначала разобраться с потоками по лучше.
Потоки запускаются методом start(), а не run(). В дочерних потока нельзя использовать GUI. Передача объектов-наследников QObject от потока в поток выполняется с помощью void QObject::moveToThread ( QThread * targetThread ), причем у этих объектов не должно быть владельца (parent = 0). Воспользуйся поиском, эту тему уже несколько раз обсуждали в мельчайших подробностях. ;) Название: Re: Клиент-сервер(мультитрит): передача открытого сокета из одного Thread в другой Отправлено: maxxant от Января 31, 2010, 23:26 вот это порадовало: Код: newClientThread->run(); поток должен стартовать через start(), иначе это просто вызов функции. и вот такого в примерах быть не могло, - сразу идет проверка не инициализированной переменной blockSize: Код: QDataStream in(clientSocket); Название: Re: Клиент-сервер(мультитрит): передача открытого сокета из одного Thread в другой Отправлено: bvn13 от Января 31, 2010, 23:26 Желательно сначала разобраться с потоками по лучше. пытаюсь, но что-то нормальной литературы не могу раздобыть... везде эти FortuneServer|FortuneClient... они меня уже бесят своей минималистичностью.. >:(Потоки запускаются методом start(), а не run(). а я видел в доках, что run()... хм...В дочерних потока нельзя использовать GUI. это я для отладки... потом уберу... кстати, а как логирование вести? в файл лить-то можно?Передача объектов-наследников QObject от потока в поток выполняется с помощью void QObject::moveToThread ( QThread * targetThread ), причем у этих объектов не должно быть владельца (parent = 0). да, это я тоже встретил на этом форуме, спс, буду глядеть. но насчет этого метода есть встречный вопрос. Если (взять тот же ThreatedFortuneServer) в типовых примерах есть реализация как у меня, то почему так нельзя? или это неправильно просто? но тогда опять же - почему так написано в примере от разработчиков?Воспользуйся поиском, эту тему уже несколько раз обсуждали в мельчайших подробностях. ;) Название: Re: Клиент-сервер(мультитрит): передача открытого сокета из одного Thread в другой Отправлено: bvn13 от Января 31, 2010, 23:30 вот это порадовало: Код: newClientThread->run(); поток должен стартовать через start(), иначе это просто вызов функции. вот блин.... где же я это вычитал??? хм... спасибо :) и вот такого в примерах быть не могло, - сразу идет проверка не инициализированной переменной blockSize: да, тут я апшибся... в fortuneClient (судя по логике вызовов методов) идет вот так:Код: QDataStream in(clientSocket); Код: QDataStream in(clientSocket); Название: Re: Клиент-сервер(мультитрит): передача открытого сокета из одного Thread в другой Отправлено: BRE от Января 31, 2010, 23:31 а я видел в доках, что run()... хм... run - это тело потока.это я для отладки... потом уберу... кстати, а как логирование вести? в файл лить-то можно? Для отладки нужно использовать qDebug()да, это я тоже встретил на этом форуме, спс, буду глядеть. но насчет этого метода есть встречный вопрос. Если (взять тот же ThreatedFortuneServer) в типовых примерах есть реализация как у меня, то почему так нельзя? или это неправильно просто? но тогда опять же - почему так написано в примере от разработчиков? В примерах по другому...Между потоками передается хендл сокета, а не объект. Название: Re: Клиент-сервер(мультитрит): передача открытого сокета из одного Thread в другой Отправлено: bvn13 от Января 31, 2010, 23:35 т.е. не надо реализовывать метод start()? оно само вызовет run() ? хм... читаю дальше маны... да, это я тоже встретил на этом форуме, спс, буду глядеть. но насчет этого метода есть встречный вопрос. Если (взять тот же ThreatedFortuneServer) в типовых примерах есть реализация как у меня, то почему так нельзя? или это неправильно просто? но тогда опять же - почему так написано в примере от разработчиков? В примерах по другому...Между потоками передается хендл сокета, а не объект. Название: Re: Клиент-сервер(мультитрит): передача открытого сокета из одного Thread в другой Отправлено: BRE от Января 31, 2010, 23:47 что есть хендл сокета? его дескриптор? ну так я его и передаю в одном из вариантов... и судя по отсутствию ошибок - он успешно доходит... Значит в этом варианте не нужно делать moveToThread. А если захочешь передать объект, то понадобиться. :)У тебя я нигде в run не увидел запуска цикла обработки событий, а без него система межпоточных сообщений работать не будет. Новый поток создается не в конструкторе QThread, а после вызова start. Т.е. можно сказать, что контекст потока образуется при входе в тело потока (метод run) и разрушается он при выходе из нее. Все объекты, которые будут созданы в run, будут находиться в его контексте, любые другие объекты созданные до момента входа в run нужно переносить в него с помощью moveToThread. Конечно, если с этими объектами предполагается работать в этом потоке. Лучше сначала хорошо разобраться с потоками, потом хорошо разобраться с сокетами, а потом пытаться использовать эти механизмы вместе. Иначе ты будешь только путаться и не понимать из-за чего что не работает. ;) Название: Re: Клиент-сервер(мультитрит): передача открытого сокета из одного Thread в другой Отправлено: maxxant от Января 31, 2010, 23:51 идея: при новом коннекте (slot_onNewConnection()) должен создаваться MYclientThread(public QThread), ему передаваться сокет ещё вариант реализации наследоваться от QTcpServer и перегрузить virtual void incomingConnection ( int socketDescriptor ) и из неё кидать дескриптор через сигнал в нужный поток, где и создавать сокет. Я так делал тоже. по fortune client: Код: void Client::requestNewFortune() по сути здесь blockSize особого смысла не несёт, но вот в реальных приложениях, обычно передают размер блока в начале сообщения, поскольку по сигналу readyRead() может прийти как несколько пакетов, так и часть от одного, и в цикле приходиться проверять и считывать, исходя из того сколько байт доступно в буфере сокета и каков должен быть размер пакета. Название: Re: Клиент-сервер(мультитрит): передача открытого сокета из одного Thread в другой Отправлено: bvn13 от Января 31, 2010, 23:54 Новый поток создается не в конструкторе QThread, а после вызова start. Т.е. можно сказать, что контекст потока образуется при входе в тело потока (метод run) и разрушается он при выходе из нее. Все объекты, которые будут созданы в run, будут находиться в его контексте, любые другие объекты созданные до момента входа в run нужно переносить в него с помощью moveToThread. Конечно, если с этими объектами предполагается работать в этом потоке. а, скажем, если я в своем thread-наследованном классе создам ссылочные свойства (объекты, которые мне понадобятся, объявлю ссылками), а перед запуском потока из метода, его запускающего, проинициализирую эти объекты, передав в них ссылки, на нужные мне объекты, - эти объекты я смогу нормально использовать в теле run() или все-таки moveToThread? ;) Название: Re: Клиент-сервер(мультитрит): передача открытого сокета из одного Thread в другой Отправлено: maxxant от Февраля 01, 2010, 00:14 эти объекты я смогу нормально использовать в теле run() или все-таки moveToThread? ;) всё что не создаётся в теле run() нужно делать moveToThread() и только после этого коннектить к ним сигналы/слоты (или вручную указывать при коннекте Qt::QueuedConnection). При этом помнить, что если в треде (в run() ) нет фунции exec() или QCoreApplication::processEvents() то и слоты которые QueuedConnection в этом треде обрабатываться не будут. Вообщем, курить доки. Я по началу три раза переписывал Qt-шный сетевой код, пока просветление не наступило. Название: Re: Клиент-сервер(мультитрит): передача открытого сокета из одного Thread в другой Отправлено: BRE от Февраля 01, 2010, 00:16 а, скажем, если я в своем thread-наследованном классе создам ссылочные свойства (объекты, которые мне понадобятся, объявлю ссылками), а перед запуском потока из метода, его запускающего, проинициализирую эти объекты, передав в них ссылки, на нужные мне объекты, - эти объекты я смогу нормально использовать в теле run() или все-таки moveToThread? ;) Контекст, которому принадлежат объекты имеет значение только для объектов классов-наследников QObject, для того чтобы сигнальная система нормально работала между потоками.Если такой объект создается не в методе run и с ним планируется настраивать сигнально-слотовые отношения, то необходимо перемещение объекта в контекст потока. Код
Название: Re: Клиент-сервер(мультитрит): передача открытого сокета из одного Thread в другой Отправлено: hackoff от Февраля 02, 2010, 18:32 Тоже пишу аналогичное приложение. Проблема с чтением из сокета.
В потоке создаю класс, являющийся наследником QtcpSocket, создаю там слот ready_read(). Далее в конструкторе делаю так Код: connect(this,SIGNAL(readyRead()), Так вот, когда я из КЛИЕНТА отправляю данный Код: QPixmap pix=screenShot(); И пытаюсь получить на сервере в слоте ready_read Код: void connectionTCP::ready_read(){ qDebug() выводит Цитировать a?? 0 byteArray size 8 QString "" QString size 0 a?? 1 byteArray size 2 QString "" QString size 0 a?? 2 byteArray size 12 QString "" QString size 0 a?? 3 byteArray size 1680 QString "" QString size 0 a?? 4 byteArray size 0 QString "" QString size 0 ............................................................... a?? 0 byteArray size 0 QString "" QString size 0 a?? 0 byteArray size 0 QString "" QString size 0 Почему byteArray не копируется в QString, а при этом вот такая конструкция for (int k=0;k<8;k++) send.append((char)byteArray[k]); прекрасно собирает слово. Миллион и один способ пробовал, ничего не получается :(. pix.size() - это я глупость написал :(, но сути вопроса не меняет.. Название: Re: Клиент-сервер(мультитрит): передача открытого сокета из одного Thread в другой Отправлено: maxxant от Февраля 03, 2010, 10:58 Почему byteArray не копируется в QString, а при этом вот такая конструкция for (int k=0;k<8;k++) send.append((char)byteArray[k]); прекрасно собирает слово. Миллион и один способ пробовал, ничего не получается :(. лучше миллион и один раз посмотреть доки с примерами. Вы сериализуете один тип, а десериализуется другой. Десериализация должна быть строго симметричной. Иначе результат не предсказуем. Можете для примера сравнить разницу операторов сериализации для QByteArray и QString: Код
Название: Re: Клиент-сервер(мультитрит): передача открытого сокета из одного Thread в другой Отправлено: hackoff от Февраля 03, 2010, 11:34 Идею понял! Спасибо!
Но появилась другая проблема. В клиенте пишу Код: QPixmap pix=screenShot(); На сервере читаю Код: void connectionTCP::ready_read(){ Дебаг выводит Цитировать "send-screen" QSize(-1, -1) "" "" QSize(-1, -1) "" "" QSize(-1, -1) "" .................................. "" QSize(-1, -1) "" "" QSize(-1, -1) "" Почему изображение и последняя строка не читаются? Название: Re: Клиент-сервер(мультитрит): передача открытого сокета из одного Thread в другой Отправлено: maxxant от Февраля 03, 2010, 12:44 Дебаг выводит Цитировать "send-screen" QSize(-1, -1) "" "" QSize(-1, -1) "" "" QSize(-1, -1) "" .................................. "" QSize(-1, -1) "" "" QSize(-1, -1) "" Почему изображение и последняя строка не читаются? Сигнал readyRead() присылается при получении пакета данных. Вероятно, когда вы его получаете, данные пришли ещё не все, сокет просто не может логически разделить пакеты так как вам необходимо . Возможно проблема сейчас и не в этом, но столкнуться с этим придётся, поэтому сразу реализуйте проверку на кол-во данных. Здесь на форуме уже писали (вроде и я писал) как поступить в этом случае. Есть метод bytesAvailable() у QIODevice и есть ваш пакет данных, размер которого необходимо знать до отправки, соответственно при приёме можно вычислить все ли необходимые данные уже находиться в буфере сокета, после чего считывать. Если на вскидку, то всё просто, писать сначала в QByteArray а потом его и отправлять: отправка: Код quint32 чтобы работало везде на 32-х и на 64-х битах одинаково p_ioDevice - это сокет. получение: Код
Название: Re: Клиент-сервер(мультитрит): передача открытого сокета из одного Thread в другой Отправлено: hackoff от Февраля 03, 2010, 12:48 спасибо большое. Попытаюсь применить Ваш рецепт.
|