Есть клиент (наслденик QTcpSocket) , в нем реализованы функции запроса к серверу :
client::client(QWidget *parent) :
QWidget(parent)
{
socket = new QTcpSocket(this);
this->setSocketConnections();
connect(this->connectButton,SIGNAL(clicked()),this,SLOT(connectToServer()));
}
void client::setSocketConnections()
{
connect(socket, SIGNAL(error(QAbstractSocket::SocketError)),
this, SLOT(displayError(QAbstractSocket::SocketError)));
connect(socket,SIGNAL(connected()),this,SLOT(readTask()));
}
void client::connectToServer()
{
netxBlockSize=0;
serverIp = ipLineEdit->text();
serverPort = portLineEdit->text().toInt();
socket->abort();
socket->connectToHost(serverIp,serverPort);
}
void client::readTask()
{
QByteArray block;
QDataStream out(&block,QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_6);
out << quint16(0) << 10;
out.device()->seek(0);
out << quint16 (block.size() - sizeof(quint16));
socket->write(block);
}
server::server(QObject *parent) :
QTcpServer(parent)
{
connectToDB();
QList<QHostAddress> ipAddressesList = QNetworkInterface::allAddresses();
for (int i = 0; i < ipAddressesList.size(); ++i) {
if (ipAddressesList.at(i) != QHostAddress::LocalHost &&
ipAddressesList.at(i).toIPv4Address()) {
this->listen(ipAddressesList.at(i),27015);
break;
}
}
if (this->serverAddress().isNull())
this->listen(QHostAddress::LocalHost,27015);
}
void server::incomingConnection(int socketDescriptor)
{
ClientThread * thread= new ClientThread(socketDescriptor,colors,specifications, this);
connect(thread,SIGNAL(finished()),thread,SLOT(deleteLater()));
thread->start();
}
ClientThread::ClientThread(int socketDescriptor,
const QMap <int, QString> & colors,
const QMap < int , QPair <QString , QString> > & specification,
QObject *parent ) :
socketDescriptor(socketDescriptor),
colors(colors),
specification(specification),
QThread(parent)
{
nextBlockSize = 0;
}
void ClientThread::Run()
{
socket = new QTcpSocket();
connect(socket,SIGNAL(readyRead()),this,SLOT(start()));
socket->setSocketDescriptor(socketDescriptor);
qDebug() << "HAHA";
socket->disconnectFromHost();
socket->waitForDisconnected();
}
Threaded Fortune Server Example посмотри его в ассистенте.. Там понятно написано как делать. У тебя немного неправильный подход.
connect(socket,SIGNAL(readyRead()),this,SLOT(start()));
Такое не будет работать. Создавать socket лучше в run(). И при этом создать какой-нибудь отдельный объект в том же run(), слот у которого будет обрабатывать readyRead(). Создавать объект нужно для того, чтобы socket и данный объект были созданы в одинаковом потоке. Почитайте о потоках подробнее в документации.
Т.е. что бы обработать readyRead в потоке (проще говоря - считать данные с сокета) необходимо создать этот сокет во время работы потока + что бы данные считывались не самим экземпляром потока, а неким объектом по сигналу readyRead от сокета??
================
А если соеденить readyRead сокета с слотом потока?Тоже не будет взаимодействовать, как я понимаю?
Я попробовал сделать вот так :
void ClientThread::run()
{
socket= new QTcpSocket();
socket->setSocketDescriptor(socketDescriptor);
connect(socket,SIGNAL(readyRead()),this,SLOT(readClientSocket()),Qt::QueuedConnection);
exec();
socket->disconnectFromHost();
socket->waitForDisconnected();
}
void ClientThread::readClientSocket()
{
qDebug() << "reading client";
QDataStream in(socket);
in.setVersion(QDataStream::Qt_4_6);
if (nextBlockSize == 0)
{
if (socket->bytesAvailable() < sizeof(quint16))
{
exit();
return;
}
in >> nextBlockSize;
}
if( socket->bytesAvailable() < nextBlockSize)
{
exit();
return;
}
quint8 requestType;
in >> requestType;
if(requestType == 'C')
{
QByteArray block;
QDataStream out(&block,QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_6);
out << quint16(0);
out.device()->seek(0);
out << quint16(block.size() - sizeof(quint16));
qDebug() << "before crash";
// socket->write(block); Вот здесь крашит
}
exit();
}
socket->write(block); нельзя использовать объекты из разных потоков. Т.е. void ClientThread::readClientSocket() создан и выполняется в основном потоке, а т.к. socket создан в потоке ClientThread, то использовать в другом потоке его нельзя. Соответственно, можно сделать как я предлагал(отдельный объект), либо наследовать сам qtcpsocket и определить в нем слот записи (this->write...). И вместо socket->write(block); в readClientSocket() высылать сигнал на слот записи.
Мне передать указатель на сокет в этот объект, или же просто определить слот в котором буду писать в сокет ?
А нельзя ли сокет "передвинуть" ( moveToThread() ) в clientThread поток?
Сделал объект :
#ifndef REQUESTBROCKER_H
#define REQUESTBROCKER_H
#include <QObject>
#include <QTcpSocket>
#include <QDataStream>
#include <QByteArray>
class requestBrocker : public QObject
{
Q_OBJECT
public:
explicit requestBrocker(QTcpSocket * socket, QObject *parent = 0);
int nextBlockSize;
QTcpSocket * socket;
private slots:
void readClient();
};
#endif // REQUESTBROCKER_H
#include "requestbrocker.h"
#include <QDebug>
requestBrocker::requestBrocker(QTcpSocket * socket,QObject *parent) :
QObject(parent),socket(socket)
{
nextBlockSize=0;
}
void requestBrocker::readClient()
{
qDebug() << "reading client";
QDataStream in(socket);
in.setVersion(QDataStream::Qt_4_6);
if (nextBlockSize == 0)
{
if (socket->bytesAvailable() < sizeof(quint16))
{
return;
}
in >> nextBlockSize;
}
if( socket->bytesAvailable() < nextBlockSize)
{
return;
}
quint8 requestType;
in >> requestType;
if(requestType == 'C')
{
QByteArray block;
QDataStream out(&block,QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_6);
out << quint16(0);
out.device()->seek(0);
out << quint16(block.size() - sizeof(quint16));
socket->write(block);
qDebug() << "data writed";
}
}
socket= new QTcpSocket();
socket->setSocketDescriptor(socketDescriptor);
requestBrocker * brocker = new requestBrocker(socket);
connect(socket,SIGNAL(readyRead()),brocker,SLOT(readClient()),Qt::QueuedConnection);
exec();
socket->disconnectFromHost();
socket->waitForDisconnected();
void client::sendRequest()
{
QByteArray block;
QDataStream out(&block,QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_6);
out << quint16(0) << quint8('C') << quint32(32);
out.device()->seek(0);
out << quint16 (block.size() - sizeof(quint16));
socket->write(block);
}
Ну с forever на получение полных данных я понял.но у меня другая проблема. Что бы запустить цикл обработки событий в функции run() потока я использую
exec() :
void ClientThread::run()
{
socket = new QTcpSocket();
socket->setSocketDescriptor(socketDescriptor);
requestBrocker * brocker = new requestBrocker(socket);
connect(socket,SIGNAL(readyRead()),brocker,SLOT(readClient()),Qt::QueuedConnection);
// connect(socket,SIGNAL(readyRead()),this,SLOT(readClientSocket()),Qt::QueuedConnection);
exec();
socket->disconnectFromHost();
socket->waitForDisconnected();
}
void requestBrocker::readClient()
{
qDebug() << "reading client " << socket->isValid() << " " << socket->bytesAvailable();
// QTcpSocket * socket = (QTcpSocket*)sender();
QDataStream in(socket);
in.setVersion(QDataStream::Qt_4_6);
forever{
if (nextBlockSize == 0)
{
if (socket->bytesAvailable() < sizeof(quint16))
{
break;
}
in >> nextBlockSize;
}
qDebug() << " total bytes " << nextBlockSize;
if( socket->bytesAvailable() < nextBlockSize)
{
break;
}
}
quint8 requestType;
in >> requestType;
qDebug() << "before read request is : " <<(char)requestType;
if(requestType == 'C')
{
QByteArray block;
QDataStream out(&block,QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_6);
out << quint16(0);
out.device()->seek(0);
out << quint16(block.size() - sizeof(quint16));
socket->write(block);
qDebug() << "data writed";
}
}
out << quint16(0) << quint8('C') << quint32(32);
out.device()->seek(0);
out << quint16 (block.size() - sizeof(quint16))
exec();
socket->disconnectFromHost();
socket->waitForDisconnected();
после exec() уже ничего никогда не выполниться.if (socket->bytesAvailable() < sizeof(quint16))
{
break;
}
тут return надо.Спасибо, Kibsoft, я пока решил свою проблему, но слегка по-другому. до 4х ночи тут сидел, лазил, смотрел исходники..
Форум Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)