Russian Qt Forum
Ноябрь 23, 2024, 11:41 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Клиент-сервер в блокирующем режиме  (Прочитано 5487 раз)
Magvaj
Гость
« : Август 06, 2009, 09:29 »

Коллеги, помогите! Уже три дня не пойму что не так.

Делаю клиент-сервер на основе потоков. Нужен блокирующий режим.

Вот код потока на клиенте:

Код:
ClientThread::ClientThread(QObject *parent) : QThread(parent)
{
    socket=new QSslSocket(this);
    QObject::connect(socket, SIGNAL(encrypted()), this, SLOT(socketReady()));
    QObject::connect(socket, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(socketSslErrors(const QList<QSslError> &)));
    QObject::connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError(QAbstractSocket::SocketError)));
}

void ClientThread::run()
{
    if(socket)
    {
        while(socket->state()==QAbstractSocket::ConnectedState) //пока соединены
        {
            if(socket->waitForReadyRead(30000)) //блокирующий режим- ждём данных
            {
                //данные пришли
                if(socket->bytesAvailable()!=0)
                {
                    qDebug(socket->readAll().data());
                }
            }
        }
        //поток закрывается
    }
}

void ClientThread::connect(QString host, int port)
{
    socket->connectToHostEncrypted(host, port);
}

void ClientThread::socketReady()
{
    this->start();
    socket->write("Hello, Server!");
}

void ClientThread::socketSslErrors(const QList<QSslError> &errors)
{
    qDebug("SSL error");
    socket->ignoreSslErrors();
}

void ClientThread::socketError(QAbstractSocket::SocketError socketError)
{
    qDebug("Socket error");
    qDebug(QVariant(socketError).toString().toAscii());
    qDebug(socket->errorString().toAscii());
}

А вот на сервере(тоже называется ClientThread):

Код:
ClientThread::ClientThread(int socketDescriptor, QObject *parent) : QThread(parent)
{
    socket=new QSslSocket(this);
    if(socket->setSocketDescriptor(socketDescriptor))
    {
        socket->setLocalCertificate("./rsa/server.pem");
        socket->setPrivateKey("./rsa/server.key");
        QObject::connect(socket, SIGNAL(encrypted()), this, SLOT(socketReady()));
        QObject::connect(socket, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(socketSslErrors(const QList<QSslError> &)));
        QObject::connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError(QAbstractSocket::SocketError)));
        socket->startServerEncryption();
    }
    else
    {
        delete socket;
    }
}

void ClientThread::run()
{
    if(socket)
    {
        while(socket->state()==QAbstractSocket::ConnectedState) //пока соединены
        {
            if(socket->waitForReadyRead(30000)) //блокирующий режим- ждём данных
            {
                //данные пришли
                if(socket->bytesAvailable()!=0)
                {
                    qDebug(socket->readAll().data());
                    socket->write("Hello, Client!");
                }
            }
        }
        //поток закрывается
    }
}

void ClientThread::socketReady()
{
    this->start();
}

void ClientThread::socketSslErrors(const QList<QSslError> &errors)
{
    qDebug("SSL error");
    socket->ignoreSslErrors();
}

void ClientThread::socketError(QAbstractSocket::SocketError socketError)
{
    qDebug("Socket error");
    qDebug(QVariant(socketError).toString().toAscii());
    qDebug(socket->errorString().toAscii());
}

Так вот, программы ведут себя неадекватно при соединении... encrypted() вызывается, а после этого клиент может доставить "Hello, Server" и выпасть в SocketError -1, либо не доставить и сервер выпадет... либо вообще ничего не покажут...

Если в run() вызывать просто exec() и обрабатывать readyRead() сокета- то данные гуляют нормально... Следовательно глюк где-то в потоках... где никак не пойму... может кто увидит ошибку?
Записан
Winstrol
Гость
« Ответ #1 : Август 06, 2009, 11:34 »

Не знаю точно, где это описано, но обычно когда сокет создается в главном потоке в конструкторе
Код
C++ (Qt)
ClientThread::ClientThread
{
socket=new QSslSocket(this);
}
 
, а затем используется в созданном потоке в ClientThread::run,  полезно бывает сделать в конструкторе
Код
C++ (Qt)
socket->moveToThread(this);
 

Записан
Ruzzz
Гость
« Ответ #2 : Август 13, 2009, 21:56 »

Magvaj, вроде как нет смысла писать так:
Код
C++ (Qt)
       while(socket->state()==QAbstractSocket::ConnectedState) //пока соединены
       {
           if(socket->waitForReadyRead(30000)) //блокирующий режим- ждём данных
вот часть кода waitForReadyRead:
Код
C++ (Qt)
   if (state() == UnconnectedState) {
       /* If all you have is a QIODevice pointer to an abstractsocket, you cannot check
          this, so you cannot avoid this warning. */

//        qWarning("QAbstractSocket::waitForReadyRead() is not allowed in UnconnectedState");
       return false;
   }
 

 
   // handle a socket in connecting state
   if (state() == HostLookupState || state() == ConnectingState) {
       if (!waitForConnected(msecs))
           return false;
   }

Как видим она проверяет на UnconnectedState, и если что вернет false, то есть достаточно оставил while с waitForReadyRead. А еще видим что она использует waitForConnected, что удобно Улыбающийся
Записан
Ruzzz
Гость
« Ответ #3 : Август 13, 2009, 22:15 »

а еще в описании waitForReadyRead есть «it returns false (if an error occurred or the operation timed out)» — возвращает false если ошибка и таймаут, а если посмотреть в код то вот:
Код
C++ (Qt)
           emit error(d->socketError);
           if (d->socketError != SocketTimeoutError)
               close();
           return false;
то есть если таймаут, то она еще и закроет сокет.
Записан
ритт
Гость
« Ответ #4 : Август 14, 2009, 01:41 »

а не наоборот?
Записан
Magvaj
Гость
« Ответ #5 : Август 14, 2009, 06:41 »

Как видим она проверяет на UnconnectedState, и если что вернет false, то есть достаточно оставил while с waitForReadyRead. А еще видим что она использует waitForConnected, что удобно Улыбающийся

Благодарю за информацию... учту ;-)
Записан
Ruzzz
Гость
« Ответ #6 : Октябрь 30, 2009, 13:15 »

а не наоборот?
Точно, ошибся Улыбающийся Если таймаут, то это как бы не ошибка, иначе закрывает сокет.
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.31 секунд. Запросов: 21.