Название: Клиент-сервер в блокирующем режиме
Отправлено: 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
а не наоборот?
Точно, ошибся :) Если таймаут, то это как бы не ошибка, иначе закрывает сокет.
|