Хочу написать клент-серверное приложение на Qt, как я понимаю мне нужно использовать классы QTcpServer и QTcpSocket.
Но что-то я не могу понять, почему при соединении не вызывается newConnection, в моей классе производном от QTcpServer, хотя функция вроде виртуальная. И пока не совсем понятно, как строить взаимодействие слушающего сокета с соединениями.
Ну все достаточно просто, если разобраться. Попробую набросать пример:
Класс производный от QTcpServer, собственно сам сервер:
class CxServer :public QTcpServer
{
Q_OBJECT
private:
CxInteraction *m_pInteraction;
public:
CxServer(QObject *pParent = 0);
virtual ~CxServer(void);
protected:
void incomingConnection( int nSocket);
};
CxServer::CxServer(QObject *pParent): QTcpServer( pParent)
{
m_pInteraction = new CxInteraction();
}
CxServer::~CxServer(void)
{
if( m_pInteraction)
{
delete m_pInteraction;
m_pInteraction = 0;
}
}
void CxServer::incomingConnection( int nSocket)
{
m_pInteraction->AddConnection( nSocket);
}
qint16 qnPort = 80;
if( !server.listen( QHostAddress::Any, qnPort))
{
QString szError = server.errorString();
qDebug() << "Error: " << szError;
}
else
{
qDebug() << "Listening port: " << qnPort;
}
class CxInteraction: public QObject
{
Q_OBJECT
public:
CxInteraction(void){}
virtual ~CxInteraction(void){}
public:
bool AddConnection( qint32 qnSocket);
private:
CxConnectionThread *CreateThread( qint32 qnSocket);
private slots:
void CloseThread();
};
bool CxInteraction::AddConnection( qint32 qnSocket)
{
return CreateThread( qnSocket) != 0;
}
CxConnectionThread *CxInteraction::CreateThread( qint32 qnSocket)
{
CxConnectionThread *pThread = 0;
try
{
pThread = new CxConnectionThread( qnSocket, this);
connect( pThread, SIGNAL( finished()), this, SLOT( CloseThread()));
pThread->start();
qDebug( "Begin thread: 0x%x", pThread);
}
catch(...)
{
qCritical( "Error in file: %s, line: %d %s", __FILE__, __LINE__, __FUNCSIG__);
if( pThread)
{
delete pThread;
pThread = 0;
}
}
return pThread;
}
void CxInteraction::CloseThread()
{
if( CxConnectionThread *pThread = qobject_cast<CxConnectionThread *>(sender()))
{
qDebug( "End thread: 0x%x", pThread);
pThread->deleteLater();
}
}
class CxConnectionThread :public QThread
{
Q_OBJECT
protected:
qint32 m_qnSocket;
const CxInteraction * const m_pInteraction;
public:
CxConnectionThread( qint32 qnSocket, QObject *pParent);
virtual ~CxConnectionThread(void);
protected:
void run(void);
void removeConnection( CxConnection *pConnection);
private slots:
void newConnection( CxConnection *pConnection);
void connectionError( QAbstractSocket::SocketError socketError);
void disconnected();
void destroyed( QObject *pObj = 0);
};
CxConnectionThread::CxConnectionThread( qint32 qnSocket, QObject *pParent):QThread( pParent), m_pInteraction( (CxInteraction*)pParent)
{
m_qnSocket = qnSocket;
}
CxConnectionThread::~CxConnectionThread(void)
{
}
void CxConnectionThread::newConnection( CxConnection *pConnection)
{
connect( pConnection, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(connectionError(QAbstractSocket::SocketError)));
connect( pConnection, SIGNAL(disconnected()), this, SLOT(disconnected()));
connect( pConnection, SIGNAL(destroyed()), this, SLOT(destroyed()));
}
void CxConnectionThread::disconnected()
{
if( CxConnection *pConnection = qobject_cast<CxConnection *>(sender()))
removeConnection( pConnection);
}
void CxConnectionThread::connectionError( QAbstractSocket::SocketError socketError)
{
if( CxConnection *pConnection = qobject_cast<CxConnection*>(sender()))
{
removeConnection(pConnection);
}
qWarning( "Connection error: %d", socketError);
}
void CxConnectionThread::removeConnection( CxConnection *pConnection)
{
pConnection->deleteLater();
}
void CxConnectionThread::destroyed( QObject *pObj)
{
this->exit();
}
void CxConnectionThread::run(void)
{
try
{
CxConnection *pConnection = new CxConnection();
pConnection->setSocketDescriptor( m_qnSocket);
emit newConnection( pConnection);
}
catch(...)
{
qCritical( "Error in file: %s, line: %d %s", __FILE__, __LINE__, __FUNCSIG__);
}
exec();
}
class CxConnection :public QTcpSocket
{
Q_OBJECT
public:
CxConnection( QObject *pParent = 0);
virtual ~CxConnection(void);
signals:
void readyForUse();
void newMessage(const QString &from, const QString &message);
private slots:
void processReadyRead();
};
CxConnection ::CxConnection (QObject *pParent): QTcpSocket( pParent)
{
QObject::connect(this, SIGNAL(readyRead()), this, SLOT(processReadyRead()));
}
CxConnection ::~CxConnection (void)
{
}
void CxHttpConnection::processReadyRead()
{
// Здесь мы можем получить пришедшие нам данные и отправить в ответ...
}
Спасибо, разобрался
привет, а почему сразу с таких сложных примеров начинать?
Помогите пожалуйста с простейшим серверком. Нужно из консольного
клиентского приложения отправить строчку и в консольном серверном приложении
вывести принятую строку в дебаг. Делаю так:
сервер:
#include <QDebug>
#include <QtNetwork>
void respServer( QTcpServer *tcpServer ){
QTcpSocket *clientSocket= tcpServer->nextPendingConnection();
const int Timeout = 5 * 1000;
while (clientSocket->bytesAvailable() < (int)sizeof(quint16)) {
if (!clientSocket->waitForReadyRead(Timeout)) {
qDebug() << "[1]" << clientSocket->error()
<< ": " << clientSocket->errorString();
return;
}
}
quint16 blockSize;
QDataStream in(clientSocket);
in.setVersion(QDataStream::Qt_4_0);
in >> blockSize;
while (clientSocket->bytesAvailable() < blockSize) {
if (!clientSocket->waitForReadyRead(Timeout)) {
qDebug() << "[2]" << clientSocket->error()
<< ": " << clientSocket->errorString();
return;
}
}
qDebug() << "BlockSize: " << blockSize;
QString nextData;
in >> nextData;
qDebug() << "Received: " << nextData;
}
int main(int argc, char *argv[])
{
QTcpServer tcpServer;
if (!tcpServer.listen(QHostAddress::Any, 33333)) {
qDebug() << QObject::tr("Unable to start the server: %1.")
.arg(tcpServer.errorString());
}
while( 1 ){
if ( tcpServer.waitForNewConnection(100) )
respServer( &tcpServer );
}
}
#include <QDebug>
#include <QtNetwork>
int main(int argc, char *argv[]){
QString serverName = "127.0.0.1";
quint16 serverPort = 33333;
const int Timeout = 5 * 1000;
QTcpSocket socket;
socket.connectToHost(serverName, serverPort);
if (!socket.waitForConnected(Timeout)) {
qDebug()<< "[1] " << socket.error()
<< ": " << socket.errorString();
return 1;
}
if (!socket.waitForReadyRead(Timeout)) {
qDebug()<< "[2] " << socket.error()
<< ": " << socket.errorString();
return 2;
}
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_0);
out << (quint16)0;
out << "Hello!!!";
out.device()->seek(0);
out << (quint16)(block.size() - sizeof(quint16));
socket.write( block );
socket.disconnectFromHost();
return 0;
}
Гость_antoshib_*
начни со стандартных примеров поставляемых с библиотекой.
Есть вопрос по поводу передачи данных. Вот на этом участке кода
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_0);
out << (quint16)0; // конец блока
out << "Hello!!!"; // сообщение
out.device()->seek(0); // ? установка позиции на начало блока?
out << (quint16)(block.size() - sizeof(quint16)); // размер блока сообщения
socket.write( block );
socket.disconnectFromHost();
Никто не объяснит?
Ну так и серилизуй все что нужно в out.
Так что ли?
out << (quint16)0; // конец блока
out << "Hello!!!"; // сообщение
out << 12345;
out << someobject;
out.device()->seek(0); // ? установка позиции на начало блока?
out << (quint16)(block.size() - sizeof(quint16)); // размер блока сообщения
Да, так.
Формируешь пакет и после этого устанавливаешь его размер.
Ну вот в том то и дело не получается правильно его потом принять.
Форум Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)