crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )


  Ответ в Как правильно читать данные с многопоточным сервером?
Введите ваше имя
Подтвердите код

Введите в поле код из 6 символов, отображенных в виде изображения. Если вы не можете прочитать код с изображения, нажмите на изображение для генерации нового кода.
 

Опции сообщения
 Включить смайлы?
Иконки сообщения
(Опционально)
                                
                                
  [ Без иконки ]
 


Последние 10 сообщений [ в обратном порядке ]
Andrewshkovskii Дата 17.5.2010, 12:41
  Спасибо, Kibsoft, я пока решил свою проблему, но слегка по-другому. до 4х ночи тут сидел, лазил, смотрел исходники..:)
Litkevich Yuriy Дата 17.5.2010, 12:37
 
Цитата(kibsoft @ 17.5.2010, 16:15) *
уже ничего никогда не выполниться
если прервать цикл обработки событий, то управление из exec() вернётся.
kibsoft Дата 17.5.2010, 12:15
 
exec();
    socket->disconnectFromHost();
    socket->waitForDisconnected();
после exec() уже ничего никогда не выполниться.

if (socket->bytesAvailable() < sizeof(quint16))
         {
             break;
         }
тут return надо.

exit можно связать с сигналом disconnected сокета, а при создании объекта ClientThread в сервере - указать deleteLayer, чтобы объект удалялся при выходе из цикла событий.
Andrewshkovskii Дата 16.5.2010, 21:51
  Ну с forever на получение полных данных я понял.но у меня другая проблема. Что бы запустить цикл обработки событий в функции run() потока я использую
exec() :
void ClientThread::run()
{
    socket = new QTcpSocket();
    socket->setSocketDescriptor(socketDescriptor);
    requestBrocker * brocker = new requestBrocker(socket);
    connect(socket,SIGNAL(readyRead()),brocker,SLOT(readClient()),Qt::QueuedConnection);
//    connect(socket,SIGNAL(readyRead()),this,SLOT(readClientSocket()),Qt::QueuedConnection);
    exec();
    socket->disconnectFromHost();
    socket->waitForDisconnected();
}

Если не запускать - брокер не поймает сигнал , и ничего не произойдет.
И вот ещё насчет брокера запросов..
:
void requestBrocker::readClient()
{
qDebug() << "reading client " << socket->isValid() << " " << socket->bytesAvailable();
// QTcpSocket * socket = (QTcpSocket*)sender();
QDataStream in(socket);
in.setVersion(QDataStream::Qt_4_6);
forever{
     if (nextBlockSize == 0)
     {
         if (socket->bytesAvailable() < sizeof(quint16))
         {
             break;
         }
         in >> nextBlockSize;
     }

     qDebug() <<  " total bytes " << nextBlockSize;
     if( socket->bytesAvailable() < nextBlockSize)
     {
         break;
     }
}
quint8 requestType;
in >> requestType;
qDebug() << "before read request is : " <<(char)requestType;
if(requestType == 'C')
{
     QByteArray block;
     QDataStream out(&block,QIODevice::WriteOnly);
     out.setVersion(QDataStream::Qt_4_6);
     out << quint16(0);
     out.device()->seek(0);
     out << quint16(block.size() - sizeof(quint16));
     socket->write(block);
     qDebug() << "data writed";
}
}


Я получаю на такие данные
    out << quint16(0) << quint8('C') << quint32(32);
    out.device()->seek(0);
    out << quint16 (block.size() - sizeof(quint16))


вот такой отладочный вывод :
Цитата
reading client true 7
total bytes 344832
before read request is :

И поток не завершается без exit() , т.е. поток остается в незавершенном режиме и не удаляется. Из брокера я не могу вызвать ни exec() ни exit, разве что явно указать parent'a ему, и через указатель на родителя вызывать.
Но основная проблема в том, что я не могу никак написать код, который бы читал/принимал данные корректно.
kibsoft Дата 16.5.2010, 18:21
 
Цитата
А нельзя ли сокет "передвинуть" ( moveToThread() ) в clientThread поток?

1) Socket и находиться в потоке clientThread(т.к. он определен в этом классе). А сам clientThread находиться в основном потоке. Т.е. есть основной поток, который создал clientThread(новый поток).

2) if( socket->bytesAvailable() < nextBlockSize)
{
return;
}
Косяк у тебя с первого взгляда здесь. Т.е. когда не все данные пришли ты выходишь из слота, но в следующий раз у тебя слот опять будет читать размер пакета и следовательно все нарушится(читать будет не те данные). Ну и естественно в requestType у тебя случайные данные.. Поэтому лучше сделай цикл бесконечный. В Шлее книге есть пример принятия.
Andrewshkovskii Дата 16.5.2010, 16:09
  Мне передать указатель на сокет в этот объект, или же просто определить слот в котором буду писать в сокет ?
А нельзя ли сокет "передвинуть" ( moveToThread() ) в clientThread поток?

Сделал объект :
#ifndef REQUESTBROCKER_H
#define REQUESTBROCKER_H

#include <QObject>
#include <QTcpSocket>
#include <QDataStream>
#include <QByteArray>

class requestBrocker : public QObject
{
Q_OBJECT
public:
    explicit requestBrocker(QTcpSocket * socket, QObject *parent = 0);
    int nextBlockSize;
    QTcpSocket * socket;
private slots:
    void readClient();

};

#endif // REQUESTBROCKER_H


#include "requestbrocker.h"
#include <QDebug>

requestBrocker::requestBrocker(QTcpSocket * socket,QObject *parent) :
    QObject(parent),socket(socket)
{
    nextBlockSize=0;
}

void requestBrocker::readClient()
{
qDebug() << "reading client";
QDataStream in(socket);
in.setVersion(QDataStream::Qt_4_6);
if (nextBlockSize == 0)
{
     if (socket->bytesAvailable() < sizeof(quint16))
     {
         return;
     }
     in >> nextBlockSize;
}
if( socket->bytesAvailable() < nextBlockSize)
{
     return;
}
quint8 requestType;
in >> requestType;
if(requestType == 'C')
{
     QByteArray block;
     QDataStream out(&block,QIODevice::WriteOnly);
     out.setVersion(QDataStream::Qt_4_6);
     out << quint16(0);
     out.device()->seek(0);
     out << quint16(block.size() - sizeof(quint16));
     socket->write(block);
     qDebug() << "data writed";
}
}


И код run() :
    socket= new QTcpSocket();
    socket->setSocketDescriptor(socketDescriptor);
    requestBrocker * brocker = new requestBrocker(socket);
    connect(socket,SIGNAL(readyRead()),brocker,SLOT(readClient()),Qt::QueuedConnection);
    exec();
    socket->disconnectFromHost();
    socket->waitForDisconnected();

В консоль приходит только :
reading client,
данные с сокета почему-то не считываются..
Сделал небольшую отладку.. в requestType находиться 0..получается данные куда-то делись, либо я не правильно их читаю.
Записываю вот так :
void client::sendRequest()
{
    QByteArray block;
    QDataStream out(&block,QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_4_6);
    out << quint16(0) << quint8('C') << quint32(32);
    out.device()->seek(0);
    out << quint16 (block.size() - sizeof(quint16));
    socket->write(block);
}
kibsoft Дата 16.5.2010, 15:45
  socket->write(block); нельзя использовать объекты из разных потоков. Т.е. void ClientThread::readClientSocket() создан и выполняется в основном потоке, а т.к. socket создан в потоке ClientThread, то использовать в другом потоке его нельзя. Соответственно, можно сделать как я предлагал(отдельный объект), либо наследовать сам qtcpsocket и определить в нем слот записи (this->write...). И вместо socket->write(block); в readClientSocket() высылать сигнал на слот записи.
Andrewshkovskii Дата 16.5.2010, 15:04
  Я попробовал сделать вот так :
void ClientThread::run()
{
    socket= new QTcpSocket();
    socket->setSocketDescriptor(socketDescriptor);
    connect(socket,SIGNAL(readyRead()),this,SLOT(readClientSocket()),Qt::QueuedConnection);
    exec();
    socket->disconnectFromHost();
    socket->waitForDisconnected();
}


void ClientThread::readClientSocket()
{
    qDebug() << "reading client";
    QDataStream in(socket);
    in.setVersion(QDataStream::Qt_4_6);
    if (nextBlockSize == 0)
    {
        if (socket->bytesAvailable() < sizeof(quint16))
        {
            exit();
            return;
        }
        in >> nextBlockSize;
    }
    if( socket->bytesAvailable() < nextBlockSize)
    {
        exit();
        return;
    }
    quint8 requestType;
    in >> requestType;
    if(requestType == 'C')
    {
        QByteArray block;
        QDataStream out(&block,QIODevice::WriteOnly);
        out.setVersion(QDataStream::Qt_4_6);
        out << quint16(0);
        out.device()->seek(0);
        out << quint16(block.size() - sizeof(quint16));
        qDebug() << "before crash";
//        socket->write(block); Вот здесь крашит
    }
    exit();
}


Крашит с таким сообщением :
Цитата
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 Дата 15.5.2010, 19:45
 
Цитата(Andrewshkovskii @ 15.5.2010, 20:21) *
Т.е. что бы обработать readyRead в потоке (проще говоря - считать данные с сокета) необходимо создать этот сокет во время работы потока + что бы данные считывались не самим экземпляром потока, а неким объектом по сигналу readyRead от сокета??

Да, т.к. экземпляр потока создан в другом потоке, поэтому нельзя делать connect с DirectConnection, т.е. чтобы слот вызывался сразу после испускания сиглнала. По-моему можно QueuedConnection, но я не пробовал так. Signals and Slots Across Threads - тут в ассистенте описание.
P.S. Qt::QueuedConnection - при генерации сигнал помещается в очередь обработки событий.
Andrewshkovskii Дата 15.5.2010, 19:21
  Т.е. что бы обработать readyRead в потоке (проще говоря - считать данные с сокета) необходимо создать этот сокет во время работы потока + что бы данные считывались не самим экземпляром потока, а неким объектом по сигналу readyRead от сокета??
================
А если соеденить readyRead сокета с слотом потока?Тоже не будет взаимодействовать, как я понимаю?
Просмотр темы полностью (откроется в новом окне)
RSS Текстовая версия Сейчас: 29.3.2024, 11:54