crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )

2 страниц V   1 2 >  
Ответить в данную темуНачать новую тему
> QTcpServer и QTcpSocket, как с ними работать?
ubuntu
  опции профиля:
сообщение 10.10.2007, 16:12
Сообщение #1


Студент
*

Группа: Новичок
Сообщений: 32
Регистрация: 10.10.2007
Пользователь №: 9

Спасибо сказали: 0 раз(а)




Репутация:   0  


Хочу написать клент-серверное приложение на Qt, как я понимаю мне нужно использовать классы QTcpServer и QTcpSocket.
Но что-то я не могу понять, почему при соединении не вызывается newConnection, в моей классе производном от QTcpServer, хотя функция вроде виртуальная. И пока не совсем понятно, как строить взаимодействие слушающего сокета с соединениями.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
ViGOur
  опции профиля:
сообщение 10.10.2007, 16:40
Сообщение #2


Мастер
******

Группа: Модератор
Сообщений: 3296
Регистрация: 9.10.2007
Из: Москва
Пользователь №: 4

Спасибо сказали: 231 раз(а)




Репутация:   40  


Ну все достаточно просто, если разобраться. Попробую набросать пример:
Класс производный от 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;
    }


При получении соединения вызывается incomingConnection в котором полученное соединение добавляется в обработчик соединений, класс CxInteraction.
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()
{
    // Здесь мы можем получить пришедшие нам данные и отправить в ответ...
}


Вот и все, что от тебя требуется. :)
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
ubuntu
  опции профиля:
сообщение 11.10.2007, 8:09
Сообщение #3


Студент
*

Группа: Новичок
Сообщений: 32
Регистрация: 10.10.2007
Пользователь №: 9

Спасибо сказали: 0 раз(а)




Репутация:   0  


Спасибо, разобрался
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Гость_antoshib_*
сообщение 21.4.2010, 11:39
Сообщение #4





Гости








    


привет, а почему сразу с таких сложных примеров начинать?

Помогите пожалуйста с простейшим серверком. Нужно из консольного
клиентского приложения отправить строчку и в консольном серверном приложении
вывести принятую строку в дебаг. Делаю так:

сервер:
Раскрывающийся текст
#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;
}


все запускается, но соединение сбрасывается.. ((
Причина редактирования: codebox - неудобен
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
kwisp
  опции профиля:
сообщение 22.4.2010, 9:22
Сообщение #5


астарожна ынтжинэр
*****

Группа: Участник
Сообщений: 1404
Регистрация: 26.11.2008
Из: ТаганрогРодинаЧехова
Пользователь №: 435

Спасибо сказали: 113 раз(а)




Репутация:   23  


Гость_antoshib_*
начни со стандартных примеров поставляемых с библиотекой.

Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Гость_antoshib_*
сообщение 24.4.2010, 9:32
Сообщение #6





Гости








    


Цитата(kwisp @ 22.4.2010, 9:22) *
Гость_antoshib_*
начни со стандартных примеров поставляемых с библиотекой.


С них и начал.. Но там сразу предлагается через потоки делать - не наглядно совсем!

выкрутился пока так, в сервере:
CODE

....

char *rb = new char( blockSize );
uint br = (uint) blockSize;

in.readBytes( rb, br );
qDebug() << "Received: " << rb;

delete[] rb;
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Gambit
  опции профиля:
сообщение 14.7.2010, 17:16
Сообщение #7


Новичок


Группа: Новичок
Сообщений: 4
Регистрация: 12.6.2010
Пользователь №: 1802

Спасибо сказали: 0 раз(а)




Репутация:   0  


Цитата(ViGOur @ 10.10.2007, 16:40) *
const CxInteraction * const m_pInteraction;
Ругается ((((
..\network_demo_1\/networkdemo.h:85: error: ISO C++ forbids declaration of 'CxInteraction' with no type
..\network_demo_1\/networkdemo.h:85: error: expected ';' before '*' token

Ну и далеее
Цитата
CxConnectionThread::CxConnectionThread( qint32 qnSocket, QObject *pParent):QThread( pParent), m_pInteraction( (CxInteraction*)pParent)
{
m_qnSocket = qnSocket;
}

..\network_demo_1\/networkdemo.h: In constructor 'CxConnectionThread::CxConnectionThread(qint32, QObject*)':
..\network_demo_1\/networkdemo.h:102: error: class 'CxConnectionThread' does not have any field named 'm_pInteraction'
..\network_demo_1\/networkdemo.h:102: error: 'CxInteraction' was not declared in this scope
..\network_demo_1\/networkdemo.h:102: error: expected primary-expression before ')' token
In file included from ..\network_demo_1\main.cpp:2:
..\network_demo_1\/networkdemo.h: In member function 'virtual void CxConnectionThread::run()':

Цитата
qCritical( "Error in file: %s, line: %d %s", __FILE__, __LINE__, __FUNCSIG__);

..\network_demo_1\/networkdemo.h:153: error: '__FUNCSIG__' was not declared in this scope
..\network_demo_1\/networkdemo.h: In member function 'CxConnectionThread* CxInteraction::CreateThread(qint32)':
..\network_demo_1\/networkdemo.h:193: warning: format '%x' expects type 'unsigned int', but argument 2 has type 'CxConnectionThread*'
..\network_demo_1\/networkdemo.h:197: error: '__FUNCSIG__' was not declared in this scope
..\network_demo_1\/networkdemo.h: In member function 'void CxInteraction::CloseThread()':
..\network_demo_1\/networkdemo.h:212: warning: format '%x' expects type 'unsigned int', but argument 2 has type 'CxConnectionThread*'
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
sidsukana
  опции профиля:
сообщение 8.8.2011, 17:10
Сообщение #8


Участник
**

Группа: Участник
Сообщений: 158
Регистрация: 23.12.2010
Из: Челябинск
Пользователь №: 2296

Спасибо сказали: 10 раз(а)




Репутация:   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();


А что если нужно отправить не только текст, а допустим число, или объект в одном этом блоке? Как это сделать, примеров не нашел.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
sidsukana
  опции профиля:
сообщение 9.8.2011, 15:48
Сообщение #9


Участник
**

Группа: Участник
Сообщений: 158
Регистрация: 23.12.2010
Из: Челябинск
Пользователь №: 2296

Спасибо сказали: 10 раз(а)




Репутация:   2  


Никто не объяснит?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
BRE
  опции профиля:
сообщение 9.8.2011, 21:51
Сообщение #10


Профессионал
*****

Группа: Участник
Сообщений: 1112
Регистрация: 6.3.2009
Из: Ростов-на-Дону
Пользователь №: 591

Спасибо сказали: 264 раз(а)




Репутация:   44  


Ну так и серилизуй все что нужно в out.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

2 страниц V   1 2 >
Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0




RSS Текстовая версия Сейчас: 26.12.2024, 13:23