Russian Qt Forum

Qt => Работа с сетью => Тема начата: Magvaj от Августа 06, 2009, 09:29



Название: Клиент-сервер в блокирующем режиме
Отправлено: 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() сокета- то данные гуляют нормально... Следовательно глюк где-то в потоках... где никак не пойму... может кто увидит ошибку?


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



Название: Re: Клиент-сервер в блокирующем режиме
Отправлено: Ruzzz от Августа 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, что удобно :)


Название: Re: Клиент-сервер в блокирующем режиме
Отправлено: Ruzzz от Августа 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;
то есть если таймаут, то она еще и закроет сокет.


Название: Re: Клиент-сервер в блокирующем режиме
Отправлено: ритт от Августа 14, 2009, 01:41
а не наоборот?


Название: Re: Клиент-сервер в блокирующем режиме
Отправлено: Magvaj от Августа 14, 2009, 06:41
Как видим она проверяет на UnconnectedState, и если что вернет false, то есть достаточно оставил while с waitForReadyRead. А еще видим что она использует waitForConnected, что удобно :)

Благодарю за информацию... учту ;-)


Название: Re: Клиент-сервер в блокирующем режиме
Отправлено: Ruzzz от Октября 30, 2009, 13:15
а не наоборот?
Точно, ошибся :) Если таймаут, то это как бы не ошибка, иначе закрывает сокет.