crossplatform.ru

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


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

Введите в поле код из 6 символов, отображенных в виде изображения. Если вы не можете прочитать код с изображения, нажмите на изображение для генерации нового кода.
Теги
Выровнять по центру
Ссылка на тему
Ссылка на сообщение
Скрытый текст
Сокращение
Код с подсветкой
Offtopic
 
Удалить форматирование
Спец. элементы
Шрифт
Размер
 
Цвет шрифта
 
Отменить ввод
Вернуть ввод
Полужирный
Курсив
Подчеркнутый
 
 
Смайлики
Вставить изображение
Вставить адрес электронной почты
Цитата
Код
Раскрывающийся текст
 
Увеличить отступ
По левому краю
По центру
По правому краю
Вставить список
Вставить список

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


Последние 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 Рейтинг@Mail.ru Текстовая версия Сейчас: 4.7.2025, 23:11