Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Обрыв соединения QTcpSocket
Форум на CrossPlatform.RU > Библиотеки > Qt > Qt Ввод/Вывод, Сеть. Межпроцессное взаимодействие
OrSOn
Всем добрый день! Столкнулся с довольно неприятной проблемой при работе с сокетами... Суть проблемы в следующем:

Имеется сервер и клиент, для общения используют сокеты. В некий момент времени клиент рушится (ну или связь падает, не суть важно), при этом сервер пытается что-то писать в сокет, что приводит к ошибке. Чтобы избежать этого, пробовал ввести проверку

if( tcpSocket->state() != 3 )
    return;
tcpSocket->flush();


Так вот случаются ситуации, что проверка состояния проходит, а сразу после нее до начала проталкивания информации клиент падает и на tcpSocket->flush() снова вылетаю с ошибкой.

Если кто сталкивался с подобным, подскажите, пожалуйста, как это можно обойти...
sploid
так в чем проблема? в том что сервер не знает записаны данные или нет?
SABROG
Цитата(OrSOn @ 16.2.2010, 14:47) *
вылетаю с ошибкой.


С какой именно и куда? Обрабатывать ошибку никак нельзя что ли?
OrSOn
Обработать ошибку нельзя - полностью прерывается дебаг и вылетаю, ошибка получается в том, что я пытаюсь записать информацию в сокет, который имеет состояние disconnected(), причем это состояние он получает в процессе выполнения команды записи, т.е. заранее это не отследить. Грубо говоря, получается такая ситуация:

1. Сокет подключен, начинается запись (запускается стандартная функция Qt)
2. Прямо во время записи рвется соединение
3. Половина функции прошла, а во второй оказывается, что соединения нет и вылетает ошибка...
BRE
Цитата(OrSOn @ 17.2.2010, 10:07) *
Обработать ошибку нельзя - полностью прерывается дебаг и вылетаю, ошибка получается в том, что я пытаюсь записать информацию в сокет, который имеет состояние disconnected(), причем это состояние он получает в процессе выполнения команды записи, т.е. заранее это не отследить. Грубо говоря, получается такая ситуация:

1. Сокет подключен, начинается запись (запускается стандартная функция Qt)
2. Прямо во время записи рвется соединение
3. Половина функции прошла, а во второй оказывается, что соединения нет и вылетает ошибка...

Покажи код, как ты это делаешь. Никаких вылетов быть не должно.
OrSOn
while( tmpLength < file.size() )
    {
        if( file.size() - tmpLength > blockLength )
            tmpBlock = blockLength;
        else
            tmpBlock = file.size() - tmpLength;

        char * dataBlock = new char[ tmpBlock ];

        file.read( dataBlock, tmpBlock );

        if( !tcpSocket || freeThread )
            return;
        else
            if( tcpSocket->state() != 3 )
                return;
        tcpSocket->write( dataBlock, tmpBlock );

        if( !tcpSocket || freeThread )
            return;
        else
            if( tcpSocket->state() != 3 )
                return;
        while( tcpSocket->flush() )
        {
            if( !tcpSocket || freeThread )
                return;
            else
                if( tcpSocket->state() != 3 )
                    return;
            continue;
        }

        delete []dataBlock;

        tmpLength += tmpBlock;
    }


Вот, это "тот самый" кусок примера... Как видно, уже везде, где только можно, включена проверка на разрывы

if( !tcpSocket || freeThread )
    return;
else
    if( tcpSocket->state() != 3 )
        return;


Тем не менее, на строке while( tcpSocket->flush() ) вылетает ошибка, потому что разрыв умудряется произойти во время выполнения...

З.Ы. чтобы не так нагромождено все было, вот изначальный код без проверок

while( tmpLength < file.size() )
    {
        if( file.size() - tmpLength > blockLength )
            tmpBlock = blockLength;
        else
            tmpBlock = file.size() - tmpLength;

        char * dataBlock = new char[ tmpBlock ];

        file.read( dataBlock, tmpBlock );

        tcpSocket->write( dataBlock, tmpBlock );

        while( tcpSocket->flush() )
            continue;

        delete []dataBlock;

        tmpLength += tmpBlock;
    }

BRE
Покажи как создается объект tcpSocket и какие сигналы обрабатываются.

Ты уверен, что этот объект не разрушается где-то еще (вижу там какой-то freeThread)?

Все эти проверки не нужны, ошибка где-то в другом месте.
У тебя течет память для буфера dataBlock, при любой ошибки - она не удаляется.
Зачем цикл у flush?
OrSOn
Значит по порядку...
Объект создается нормально, но в другом классе (раньше все работало, пока я не стал разбивать файлы на блоки, т.е. когда файл отсылал целиком, никаких ошибок не было). Суть в следующем: есть управляющий класс,в нем QTcpServer. Когда поступает запрос подключения, создается сокет, затем он добавляется в очередь. А далее из очереди сокеты передаются в заранее созданные потоки на обработку, после чего возвращаются обратно в очередь.

Насчет не освобождается память - я в курсе, это не страшно в данном случае (ошибки от этого не возникнет), потом устраню, когда разберусь, где все рушится.

Цикл сделан тоже неспроста... Раньше было без него, но столкнулся с некоторой проблемой - длинные файлы просто не передавались целиком, т.е. часть файла принималась с клиентской стороны, а потом сигналы readyRead() просто переставали приходить, т.е. каким-то образом остатки файла не проталкивались, хотя сервер и уходил дальше в eventLoop... Да и не в этом проблема, он рушится даже на первом вызове... Вот и не могу понять, почему при неизменном коде все работало при отправке файлов целиком и стало рушится при разбиении на блоки...

И кстати, проверки, все же, нужны, но несколько для других целей - чтобы остановить выполнение функции после разрыва соединения, иначе будет путаница с данными, если этот сокет разорвался, а потоку дали другой на обработку... И новый сокет "завершит" действия, которые предназначались не ему.
BRE
Класс TcpSocket данные кеширует сам и отправляет их блоками. Происходит это в цикле обработки событий.

Ты не показал код..., но мне кажется, что при разрыве соединения сам объект на который указывает tcpSocket разрушается (например в другом потоке), и ты пытаешься использовать уже разрушенный объект.

Метод write возвращает размер реально записанных данных, не всегда все данные могут поместиться в буфер отправки TCP-стека (хотя Qt и кеширует их сам). Эту ситуацию так же нужно обрабатывать.
OrSOn
Увы, но удаления объекта не происходит. Я уже думал об этом, поэтому тупо закомментировал ВСЕ места, где происходит удаление - результата нет. А насчет обработки записи, flush() записывает максимально возможное количество информации (не дожидаясь возвращения в цикл обработки событий), поэтому помещение его в цикл (пока записывается) как раз и осуществляет эту обработку (я уже проверял на файлах по 1.36 гигабайта). И если соединение не рвать, тов се работает и передается отлично, ломается только при закрытии клиента.

З.Ы. как говорит ассистант, мы не можем использовать flush() для сокетов, у которых состояние не connected(), так что рушится оно неспроста... А вот как обойти - хз.

З.З.Ы. код показать не могу, ибо там слишком много и все в разных классах... Но если конкретно создание сокета интересует, то вот оно:

 
if (tcpServer->hasPendingConnections()==FALSE)
        return;
    
tcpSocket = tcpServer->nextPendingConnection();
connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(readFortune()), Qt::QueuedConnection);
tcpSocket->reset();

tcpSocket->write((QString::number((int)((void *)tcpSocket))).toLocal8Bit());

tcpSocket->flush();

tmpSocketList.append( tcpSocket );


Это содержимое слота, который обрабатывает сигнал newConnection()
BRE
Ну так если ты хочешь отправлять синхронно, то попробуй вместо flush крутить цикл обработки событий.
OrSOn
Боюсь, что так будет не лучше, ибо сложнее отследить, когда данные передались полностью... Понять бы, как тут избежать вылетов..
BRE
Как только ты записал последний кусок данных в сокет и метод write это подтвердил.
Дальше забота Qt.
OrSOn
Попробовал, ничего не вышло... Вот код:
while( tmpLength < file.size() )
    {
        if( file.size() - tmpLength > blockLength )
            tmpBlock = blockLength;
        else
            tmpBlock = file.size() - tmpLength;

        char * dataBlock = new char[ tmpBlock ];

        file.read( dataBlock, tmpBlock );
        
        char * tmpPointer;
        int tmpSize = tcpSocket->write( dataBlock, tmpBlock );
        QCoreApplication::processEvents();
        while( tmpSize < tmpBlock )
        {
            tmpPointer = dataBlock + tmpSize;
            tmpSize += tcpSocket->write( tmpPointer, tmpBlock - tmpSize );
            QCoreApplication::processEvents();
        }

        delete []dataBlock;

        tmpLength += tmpBlock;
    }


Результат, как я и говорил, плачевный - в сокет НИЧЕГО не передается, вообще ничего... Без flush() упорно отказывается отсылать
BRE
Набросал небольшой пример (клиент/сервер) для передачи больших файлов. Вроде все работает, даже если клиент посылает запрос и выходит, не дожидаясь чтения файла.
В файле сервера укажи имя существующего большого файла.
OrSOn
Спасибо, сейчас гляну

Что-то я не совсем понял...

int writed = write( buf ); - грубо говоря, записали и проверили, сколько именно записалось.. Но ведь нету проверки, что записалось ВСЕ, вдруг часть не записалась... Просто проблема в том, что размер блока может быть переменным и если сделать его, скажем, пару мегабайт, все может сломаться...
BRE
Цитата(OrSOn @ 17.2.2010, 17:12) *
int writed = write( buf ); - грубо говоря, записали и проверили, сколько именно записалось.. Но ведь нету проверки, что записалось ВСЕ, вдруг часть не записалась... Просто проблема в том, что размер блока может быть переменным и если сделать его, скажем, пару мегабайт, все может сломаться...

Данные попали в буфер отправки tcp-стека, дальше это проблема стека. Если какой-то пакет потеряется, то сам протокол пере-пошлет его еще раз.
Для подтверждения же доставки всех данных, другая сторона (твой клиент) может отправить пакет твоему серверу, что бы он "успокоился".

Насчет моего кода.... Я там упростился, хотя так делать не совсем правильно. Я отправляю размер файла (переменную int) как массив char. Если архитектура на принимающей стороне будет отличаться типом хранения (byte order), то размер будет неверным. Поэтому для всех подобных передач, желательно использовать QDataStream.
OrSOn
Попробовал, но, увы, этот вариант врядли прокатит( Получается, что сначала ВЕСЬ файл записывается в сокет, а только потом клиент начинает его принимать.. А в том и проблема, именно потому и было решено отправлять файлы блоками, что в случае, если на компьютере гигабайт оперативки, а файл больше гигабайта, то он просто не уместится в память и его нельзя будет даже считать... Как и тут передать...
BRE
Цитата(OrSOn @ 18.2.2010, 13:15) *
Получается, что сначала ВЕСЬ файл записывается в сокет, а только потом клиент начинает его принимать.

Это почему так получается??? ;)
Клиент параллельно забирает данные, по мере их получения.
OrSOn
ну не знаю, я запускал в дебаге твой пример, так там клиент висел "без данных", пока сервер не переслал все полностью..
BRE
Цитата(OrSOn @ 18.2.2010, 14:35) *
ну не знаю, я запускал в дебаге твой пример, так там клиент висел "без данных", пока сервер не переслал все полностью..

Ну да, ну да.
Я там выше писал про цикл обработки событий... А у себя в примере добавить забыл. ;)
Добавь в цикл отправки сервера:
QCoreApplication::processEvents()
и все заработает.

Или уж делать полноценную асинхронную отправку, тоже сложного ничего нет.
OrSOn
Да, что-то я тоже не заметил, спасибо, так работает)) Другое дело, что полный перенос сего кода в мой проект с целью проверки ни к чему не привел... Запускаю, а клиенту ничего не приходит (пока не напишу flush()). Причем если после вызова write() написать waitForBytesWritten(), то клиент получает сигнал readyRead(), но ему приходит только маленький кусок информации,а не все сразу. Может это быть связано с тем, что сервер передает через QThread со своим циклом событий? Увы, прислать файл не могу, ибо ограничения инета, закрыто добавление файлов. Но поток сделан так:

В конструкторе

moveToThread( this );

А в функции run() одна функция exec() для создания собственного цикла. Далее работа потока идет чисто по сигналам...
BRE
Покажи подробно (закопипасть сюда) класс этого потока, скорее всего дело в нем.
Помимо переноса самого объекта потока в контекст этого потока, нужно переносить и все объекты, которые будут работать внутри него.
OrSOn
Ну все будет сложно сюда перенести, ибо много, я ключевые вещи вставлю...

Раскрывающийся текст

Объявление класса

#ifndef NTHREAD_H
#define NTHREAD_H

#include <QThread>
#include <QTcpSocket>
#include <QTimer>


struct PrioritySocket {
    QTcpSocket * tSocket;
    int prior;
};

struct HashStruct {
    QByteArray hashArr;
    QString filePath;
};

class NThread : public QThread
{
    Q_OBJECT

public:
    NThread( int num );

    void run();
    void readBD(QString & DBName,QString & DBHost, QString & DBUser,QString &  DBPassword,QString & DBDriver);
    bool isFree();
    void unlockDB( QString bName );
    void setIsFree( bool isFree );
    void stopCurrentWork();
    void updateHashMap();
    int myNum;

signals:
    void error(QTcpSocket::SocketError socketError);
    void needDB( QString bName, int threadName );
    void endThreadSocket( PrioritySocket *pSocket );
    void unlockBase( QString bName );
    void readF();

private:
    QMap<QString, HashStruct> hashMap;
    QString neededDB;
    bool dbLocked;
    QTcpSocket *tcpSocket;
    int socketDescriptor;
    QString text;
    bool HasBD;
    int CountFile;
    QString KARTADRIVER;
    QString KARTAHOST;
    QString KARTAGISDATA;
    QString KARTALISTS;
    quint32 blockSize;
    bool threadEnd;
    bool freeThread;
    PrioritySocket *priorSocket;
    bool setSocketFlag;

    int blockLength;

    void setThreadSocketFn();

public slots:
    void readFortune();
    void endThread();
    void setThreadSocket( PrioritySocket *pSocket );
    void setIsFree();
};

#endif


конструктор
NThread::NThread( int num )
: QThread(0)
{
                  myNum = num;
    moveToThread( this );
    setBaseValues();

}


Run
void NThread::run()
{
    connect( this, SIGNAL( readF() ), this, SLOT( readFortune() ), Qt::QueuedConnection );
    exec();
}


Функция установки текущего рабочего сокета на поток (сокет создается в основном потоке и передается на обратоку в один из потоков)
void NThread::setThreadSocket( PrioritySocket *pSocket )
{
    priorSocket = pSocket;    
    tcpSocket = priorSocket->tSocket;

    connect(tcpSocket, SIGNAL(disconnected()), this, SLOT(setIsFree()), Qt::DirectConnection);

    emit readF();
    connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(readFortune()), Qt::QueuedConnection);
}


Соответственно, вызывается эта функция из основного потока, после чего поток начинает реагировать на появление информации в сокете. Отвязывается сокет от потока при завершении передачи или при обрыве связи

void NThread::setIsFree()
{
    disconnect(tcpSocket, SIGNAL(disconnected()), this, SLOT(setIsFree()));
    priorSocket->prior = -1;
    emit endThreadSocket( priorSocket ); //Сигнал основному потоку, что данный сокет завершил текущую работу, удалить, если связь прервалась или поставить в очередь, если есть еще запросы с него.
    freeThread = true;
    
}



Вот примерно такая структура...
SABROG
connect( this, SIGNAL( readF() ), this, SLOT( readFortune() ), Qt::QueuedConnection );


Если ты коннектишь сигнал объекта к слоту этого же объекта, то второй указатель (this) можно опустить. Первый this опускать нельзя, т.к. метод статический, статические методы ничего не знают об объектах.

connect(tcpSocket, SIGNAL(disconnected()), this, SLOT(setIsFree()), Qt::DirectConnection);


Почему выбран именно Qt::DirectConnection? Сокет принадлежит тому же потоку, что и объект QThread?
OrSOn
Сокет принадлежит главному потоку, объект NThread тоже создается в главном потоке, но без родителя. DirectConnection() выбрано, потому что так если соединение рвется, то я НЕМЕДЛЕННО переношусь в обработку разрыва, а если оставить в очереди, то буду пытаться работать с разорванным сокетом, что приведет к ошибке и потере времени...
SABROG
Это не правильно. Соединение не должно быть прямым между двумя потоками.

Цитата
а если оставить в очереди, то буду пытаться работать с разорванным сокетом, что приведет к ошибке и потере времени...


//пытаемся читать или писать

if (socket->isValid() && socket()->state() == QAbstractSocket::ConnectingState) {
    //пишем или читаем
}


Не спасет? Потеря времени будет только если размер твоего блока 1 байт.

Если есть сомнения насчет валидности указателя socket, то его можно обернуть в QWeakPointer:

//QWeakPointer<QTcpSocket> socket;
if (socket) {
    QSharedPointer<QTcpSocket> mysock = socket->toStrongRef();
    if (mysock) {
        // чтение, запись
    }
}
OrSOn
У меня и так эта проверка стоит, согласен, можно убрать... Но проблему это не решает((( Все равно ничего не меняется..
BRE
Сокет принадлежит главному потоку, а должен принадлежать потоку, который его обслуживает.
А вообще там столько всего наверчено. Для чего?
Нужно выполнить какое-то действие - создал поток, настроил его и запустил... Он отработал, забрал у него результат, убил.
Уверен, что если распишешь задачу, можно будет все упростить в несколько раз...
SABROG
Смотри что получается. Сокет находится в гуишном потоке, его обслуживает отдельный поток, это означает, что когда ты вызываешь метод write() ты напрямую обращаешься к методу объекта. В результате ты пытаешься записать данные из одного потока в другой напрямую.

Если ты не хочешь переносить сокет в тот же поток, который его обслуживает, то убедись, что обслуживающий поток эмитит сигнал о начале записи каких-либо данных и продолжает своё выполнение в то время, когда основной поток что-то пишет в сокет. Если ты все-таки хочешь вызывать read/write в обслуживающем потоке, то сокет должен принадлежать ему. Просто запомни, что любое взаимодействие между двумя объектами находящимися в разных потоках должно происходить через сигналы или события. Не должно быть никаких прямых вызовов методов одного объекта у другого. Конечно ничего не случиться, если метод threadsafe, но таковыми являются не все.
OrSOn
Изначально так и планировалось, чтобы на 1 запрос 1 поток... Но суть в чем. Имеется система для передачи больших объемов информации (обновления данных по сети). Причем данные могут быть разнотипными (с разными приоритетами). В итоге имеем большое число возможных одновременных подключений. Если создавать отдельные потоки для каждого соединения, то их может стать слишком много и передача "умрет", будет разом обновляться у всех, но ОЧЕНЬ медленно (не из-за сети, так из-за скорости чтения с жесткого диска). Поэтому было принято решение создать заранее ограниченное количество потоков, а все запросы от клиентов распределять между ними, но не просто так, а на передачу 1 файла, т.е. клиент подключился и попал в очередь. Дошла очередь до него - сокет отправлен в поток, передается ОДИН файл и сокет попадает обратно в очередь, а потоку передают следующий. Так сделано из-за приоритетов... Если давать возможность загружать сразу все файлы, то просто приоритетные запросы файлов, необходимых срочно, будут ждать очень долго... А если создавать по одному потоку на передачу одного файла одному клиенту - это будет глупо, по-моему..

З.Ы. нагорожено там из-за некоторых дополнительных требований, они тут ни при чем)))

Цитата(SABROG @ 19.2.2010, 13:19) *
Смотри что получается. Сокет находится в гуишном потоке, его обслуживает отдельный поток, это означает, что когда ты вызываешь метод write() ты напрямую обращаешься к методу объекта. В результате ты пытаешься записать данные из одного потока в другой напрямую.

Если ты не хочешь переносить сокет в тот же поток, который его обслуживает, то убедись, что обслуживающий поток эмитит сигнал о начале записи каких-либо данных и продолжает своё выполнение в то время, когда основной поток что-то пишет в сокет. Если ты все-таки хочешь вызывать read/write в обслуживающем потоке, то сокет должен принадлежать ему. Просто запомни, что любое взаимодействие между двумя объектами находящимися в разных потоках должно происходить через сигналы или события. Не должно быть никаких прямых вызовов методов одного объекта у другого. Конечно ничего не случиться, если метод threadsafe, но таковыми являются не все.


Я не могу отдавать сокет обрабатывающему потоку, ибо потом он возвращается в главный и может быть передан затем другим... А вот насчет передачи сигналов - если так получится, то будет круто, надо попробовать)))
SABROG
Задача потока выполнять долгую операцию на фоне позволяя работать пользователю без блокировки интерфейса. Если сокет будет находится в главном потоке да еще и write() использовать, то какой смысл в отдельном потоке? write() и read() неблокирующие методы и возвращаются моментально.

Предположим, что у нас иная ситуация. На каждого клиента запускается блокирующая функция, которая производит долгие вычисления, а потом результат шлет в сокет. В этом случае нам уже нужны отдельные потоки. Задача клиента сказать потоку "посчитай мне что-то в отдельном потоке, а потом верни результат в главный поток, чтобы я мог их передать".

Если в твоем варианте такая блокирующая функция - чтение файла с диска в буффер, то файл должен читаться в отдельном потоке, формировать буффер с данными, а потом сообщать (эмитить) в основной поток, что данные готовы, типа забирай.
OrSOn
Вот я и думал об этом как раз, чтобы обрабатывающие потоки просто главному пересылали массивы информации, считанной из файла, а он уже отсылал...
BRE
OrSOn, я скоро приеду домой и сброшу тебе пример асинхронной передачи. Т.е. в момент когда сокет сможет принять данные будет генерировать сигнал, в слоте которого будет отправляться небольшой блок данных с последующем выходом из слота. При следующем проходе, опять сигнал, отправка, выход... Пока все данные не будут переданы.

Возможно, все равно придется использовать пул потоков. В Qt уже есть их реализация, посмотри на QThreadPool и QRunnable.
OrSOn
Ок, спасибо, буду ждать)
SABROG
Думаю вместо того, чтобы данные передавать с сигналом можно использовать кольцевой буффер (circular buffer, ring buffer). Можно посмотреть как он реализован в Wait Conditions Example.
BRE
Цитата(SABROG @ 19.2.2010, 14:37) *
Думаю вместо того, чтобы данные передавать с сигналом можно использовать кольцевой буффер (circular buffer, ring buffer). Можно посмотреть как он реализован в Wait Conditions Example.

А если принимающая сторона (клиент) сидит на узком канале и не успевает выбирать данные, которые ему пихают.

OrSOn
Вот новый архив, асинхронный сервер лежит в server-async. Для работы используется QSocketNotifier.
SABROG
Цитата(BRE @ 19.2.2010, 15:06) *
А если принимающая сторона (клиент) сидит на узком канале и не успевает выбирать данные, которые ему пихают.


В общем QIODevice и так использует QRingBuffer (internal class), поэтому можно просто завести буфер на базе QByteArray для каждого сокета, ловить сигнал bytesWritten() и просить (emit signal) поток подгрузить новую порцию данных, если клиенту были отправлены все данные. Поток сам очистит буффер и поместит следующий блок, затем оповестит (emit signal) об этом сокет. Сокет уже их будет писать, а поток продолжит читать данные из файлов для других сокетов и эмитить им сигналы как прочитает.
BRE
Цитата(SABROG @ 19.2.2010, 16:19) *
В общем QIODevice и так использует QRingBuffer (internal class), поэтому можно просто завести буфер на базе QByteArray для каждого сокета, ловить сигнал bytesWritten() и просить (emit signal) поток подгрузить новую порцию данных, если клиенту были отправлены все данные. Поток сам очистит буффер и поместит следующий блок, затем оповестит (emit signal) об этом сокет. Сокет уже их будет писать, а поток продолжит читать данные из файлов для других сокетов и эмитить им сигналы как прочитает.

Я немного про другое... Qt-сокеты кешируют отправляемые данные. Если же из-за каких-то проблем с сетью или низкой скорости работы принимающей стороны, реально данные по сети не уходят (буфер отправки tcp-стека переполнен), то они будут скапливаться в памяти. А сервер вместо того, что бы заниматься теми клиентами, которые готовы принимать данные, будет периодически загружать все новые куски для "тормозящего" клиента и складывать их в памяти.

Хотя... Если bytesWritten отправляется только после реальной отправки данных, то все будет нормально. Полез смотреть. :)

Да, вместо QSocketNotifier можно использовать сигнал bytesWritten().
OrSOn
Спасибо, сейчас буду пробовать все посоветованное..))
OrSOn
А такой вопрос еще... А можно ли рассматривать как вариант такой подход:

Сокеты создаются по-прежнему в главном потоке, но не имеют родителя. А когда нам надо отдать сокет на обработку, мы ему задаем moveToThread() в нужный поток, а затем также отправляем его в главный поток? По-идее, должно сработать, но что-то я не уверен в правильности такой работы. Подскажите плиз, есть шанс на успех или лучше так не делать?
SABROG
Цитата(OrSOn @ 24.2.2010, 16:10) *
а затем также отправляем его в главный поток?


Поместив однажды объект в другой поток ты его уже обратно не сможешь вернуть в первоначальный.

Цитата(OrSOn @ 24.2.2010, 16:10) *
Сокеты создаются по-прежнему в главном потоке, но не имеют родителя.


Сокеты возвращенные из метода QTcpServer::nextPendingConnection() являются детьми QTcpServer'a, стало быть и родитель у них есть.
OrSOn
А почему это я не смогу вернуть их в главный поток? А насчет родителя - всегда можно сделать setParent().

Попробовал только что, все работает вроде. Но вопрос остается открытым, могут ли быть какие-то проблемы в этой работе? Все же, я очень сомневаюсь, что разработчики Qt предусматривали использование moveToThread() для постоянной переброски объекта между потоками..
BRE
Пока я вижу один момент с перетягиванием объектов между потоками.
Qt на основании информации о расположении объекта принимает решение о том, какой тип подключения использовать при connect. Если при перемещении объекта разрывать все коннекты, а при назначении в новый поток подключать их вновь, то возможно все будет работать.
Попробуй поэкспериментировать с этим.
OrSOn
Увы, при перемещении я не могу рвать коннект, в том и суть, что надо передавать подключенным) Сейчас так и сделал, пока все работает, ошибок вызвать не получилось еще... Может и прокатит..
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Форум IP.Board © 2001-2024 IPS, Inc.