crossplatform.ru

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

5 страниц V  < 1 2 3 4 5 >  
Ответить в данную темуНачать новую тему
> Обрыв соединения QTcpSocket
BRE
  опции профиля:
сообщение 18.2.2010, 18:53
Сообщение #21


Профессионал
*****

Группа: Участник
Сообщений: 1112
Регистрация: 6.3.2009
Из: Ростов-на-Дону
Пользователь №: 591

Спасибо сказали: 264 раз(а)




Репутация:   44  


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

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

Или уж делать полноценную асинхронную отправку, тоже сложного ничего нет.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
OrSOn
  опции профиля:
сообщение 19.2.2010, 11:50
Сообщение #22


Студент
*

Группа: Участник
Сообщений: 46
Регистрация: 8.12.2009
Пользователь №: 1289

Спасибо сказали: 0 раз(а)




Репутация:   0  


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

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

moveToThread( this );

А в функции run() одна функция exec() для создания собственного цикла. Далее работа потока идет чисто по сигналам...
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
BRE
  опции профиля:
сообщение 19.2.2010, 11:59
Сообщение #23


Профессионал
*****

Группа: Участник
Сообщений: 1112
Регистрация: 6.3.2009
Из: Ростов-на-Дону
Пользователь №: 591

Спасибо сказали: 264 раз(а)




Репутация:   44  


Покажи подробно (закопипасть сюда) класс этого потока, скорее всего дело в нем.
Помимо переноса самого объекта потока в контекст этого потока, нужно переносить и все объекты, которые будут работать внутри него.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
OrSOn
  опции профиля:
сообщение 19.2.2010, 12:15
Сообщение #24


Студент
*

Группа: Участник
Сообщений: 46
Регистрация: 8.12.2009
Пользователь №: 1289

Спасибо сказали: 0 раз(а)




Репутация:   0  


Ну все будет сложно сюда перенести, ибо много, я ключевые вещи вставлю...

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

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

#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
  опции профиля:
сообщение 19.2.2010, 12:25
Сообщение #25


Профессионал
*****

Группа: Участник
Сообщений: 1207
Регистрация: 8.12.2008
Из: Russia, Moscow
Пользователь №: 446

Спасибо сказали: 229 раз(а)




Репутация:   34  


connect( this, SIGNAL( readF() ), this, SLOT( readFortune() ), Qt::QueuedConnection );


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

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


Почему выбран именно Qt::DirectConnection? Сокет принадлежит тому же потоку, что и объект QThread?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
OrSOn
  опции профиля:
сообщение 19.2.2010, 12:31
Сообщение #26


Студент
*

Группа: Участник
Сообщений: 46
Регистрация: 8.12.2009
Пользователь №: 1289

Спасибо сказали: 0 раз(а)




Репутация:   0  


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

Сообщение отредактировал OrSOn - 19.2.2010, 12:32
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
SABROG
  опции профиля:
сообщение 19.2.2010, 13:01
Сообщение #27


Профессионал
*****

Группа: Участник
Сообщений: 1207
Регистрация: 8.12.2008
Из: Russia, Moscow
Пользователь №: 446

Спасибо сказали: 229 раз(а)




Репутация:   34  


Это не правильно. Соединение не должно быть прямым между двумя потоками.

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


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

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


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

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

//QWeakPointer<QTcpSocket> socket;
if (socket) {
    QSharedPointer<QTcpSocket> mysock = socket->toStrongRef();
    if (mysock) {
        // чтение, запись
    }
}


Сообщение отредактировал SABROG - 19.2.2010, 13:07
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
OrSOn
  опции профиля:
сообщение 19.2.2010, 13:02
Сообщение #28


Студент
*

Группа: Участник
Сообщений: 46
Регистрация: 8.12.2009
Пользователь №: 1289

Спасибо сказали: 0 раз(а)




Репутация:   0  


У меня и так эта проверка стоит, согласен, можно убрать... Но проблему это не решает((( Все равно ничего не меняется..
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
BRE
  опции профиля:
сообщение 19.2.2010, 13:12
Сообщение #29


Профессионал
*****

Группа: Участник
Сообщений: 1112
Регистрация: 6.3.2009
Из: Ростов-на-Дону
Пользователь №: 591

Спасибо сказали: 264 раз(а)




Репутация:   44  


Сокет принадлежит главному потоку, а должен принадлежать потоку, который его обслуживает.
А вообще там столько всего наверчено. Для чего?
Нужно выполнить какое-то действие - создал поток, настроил его и запустил... Он отработал, забрал у него результат, убил.
Уверен, что если распишешь задачу, можно будет все упростить в несколько раз...
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
SABROG
  опции профиля:
сообщение 19.2.2010, 13:19
Сообщение #30


Профессионал
*****

Группа: Участник
Сообщений: 1207
Регистрация: 8.12.2008
Из: Russia, Moscow
Пользователь №: 446

Спасибо сказали: 229 раз(а)




Репутация:   34  


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

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

5 страниц V  < 1 2 3 4 5 >
Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0




RSS Текстовая версия Сейчас: 4.12.2024, 22:31