crossplatform.ru

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

> QThread, QEvent, QTcpServer, взаимодействия между потоками
512es
  опции профиля:
сообщение 10.11.2008, 16:00
Сообщение #1


Участник
**

Группа: Участник
Сообщений: 135
Регистрация: 31.10.2008
Пользователь №: 407

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




Репутация:   0  


всем привет!

пишу многопоточный высокопроизводительный сервер на qt.

сервер прослушивает коннекты на определённый порт и на каждое входящее соединение создаёт отдельный поток.
при каждом пришедшем пакете поток отсылает главному потоку сообщение через customEvent.

вроде работает, только не знаю как правильнее заставить все дочерние потоки (или один выборочно) отослать определённый пакет клиентам?


закинул все потоки массив QVector и передаю в customEvent главного потока ид того кто отправил. правильный путь ли я выбрал?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
3 страниц V  < 1 2 3 >  
Начать новую тему
Ответов (10 - 19)
ViGOur
  опции профиля:
сообщение 12.11.2008, 8:29
Сообщение #11


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

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

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




Репутация:   40  


Цитата(512es @ 12.11.2008, 0:43) *
через сигнал\слот что то не получилось, т.к. надо передать ещё несколько переменных..
Почему не получилось? Не вижу проблем в передаче каких бы то ни было переменных!
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
512es
  опции профиля:
сообщение 12.11.2008, 13:06
Сообщение #12


Участник
**

Группа: Участник
Сообщений: 135
Регистрация: 31.10.2008
Пользователь №: 407

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




Репутация:   0  


вообще, это мой первый проект на Qt, потому прошу сильно ногами не бить =)

вот как я пытаюсь делать:
class NetServer : public QTcpServer
{
    Q_OBJECT
public:
    NetServer(QObject *parent = 0);
    QHash<int, PThread*> Users;
private:
    int CurrentThreadNum;
protected:
    void incomingConnection(int socketDescriptor);
    void customEvent(QEvent *event);
};

void NetServer::incomingConnection(int socketDescriptor)
{
    Users.insert(++CurrentThreadNum,new PThread(socketDescriptor, this));
//    connect(this, SIGNAL(toSendMessage(QString msgString)), Users.value(CurrentThreadNum), SLOT(onSendMessage(QString msgString)));
    Users.value(CurrentThreadNum)->ThreadNumber = CurrentThreadNum;
    Users.value(CurrentThreadNum)->start();
}

void NetServer::customEvent(QEvent *event)
{
    QHashIterator<int, PThread*> i(Users);
    switch ((int)event->type()) {
    case 1234:
        MyNewMsgEvent *MyMsgEvent = (MyNewMsgEvent *)event;
        qDebug() << "Received custom Event text from user" << MyMsgEvent->SenderUser << MyMsgEvent->message;      
        while (i.hasNext()) {
            i.next();
//            i.value()->onSendMessage(QString::number(MyMsgEvent->SenderUser,10) + " " + MyMsgEvent->message);
//            qDebug() << i.value() << "ddd" << Users.value(1) << i.value()->currentThread();
            MyNewMsgEvent *ev = new MyNewMsgEvent();
            ev->message = MyMsgEvent->message;
            ev->SenderUser = MyMsgEvent->SenderUser;
            QCoreApplication::postEvent(i.value(), ev);
        }
        break;
    case 1109: // User disconnected
        EventDisconnected *EvDisconnected = (EventDisconnected *)event;
        qDebug() << "User" << EvDisconnected->SenderUser << "SignOff";
        Users.value(EvDisconnected->SenderUser)->deleteLater();
        Users.remove(EvDisconnected->SenderUser);
        qDebug() << "Stats" << Users.size();
        break;
    }
}

void PThread::onDisconnected()
{
    exit();
    EventDisconnected *ev = new EventDisconnected();
    ev->SenderUser = ThreadNumber;
    QCoreApplication::postEvent(this->parent(), ev);
}

void PThread::run()
{
    tcpSocket = new QTcpSocket;
    ...
    connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(onReadyRead()),Qt::DirectConnection);
    connect(tcpSocket, SIGNAL(disconnected()), this, SLOT(onDisconnected()),Qt::DirectConnection);
    exec();
    ...
    delete tcpSocket;
}

void PThread::customEvent(QEvent *event)
{
    switch ((int)event->type()) {
    case 1234:
        forever;
        break;
    }
}


знаю что многое ещё выгледит слишком не красиво, но сейчас мне нравное разобраться с потоками..
в дальнейшем вынесу всё управление пользователями в отдельный класс..

так вот, проблема в том что PThread::customEvent(QEvent *event) выполняется почему то в главном потоке( хотя по идее должен в дочернем..
это можно наглядно увидеть через Process Explorer. когда доходит до цикла forever вешается главный поток, а не дочерний(
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
512es
  опции профиля:
сообщение 12.11.2008, 15:02
Сообщение #13


Участник
**

Группа: Участник
Сообщений: 135
Регистрация: 31.10.2008
Пользователь №: 407

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




Репутация:   0  


попробовал через сигнал\слот..
connect(this, SIGNAL(toSendMessage(QString)), Users.value(CurrentThreadNum), SLOT(onSendMessage(QString)),Qt::DirectConnection);

всё равно в том же потоке выполняется =(
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
512es
  опции профиля:
сообщение 13.11.2008, 12:27
Сообщение #14


Участник
**

Группа: Участник
Сообщений: 135
Регистрация: 31.10.2008
Пользователь №: 407

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




Репутация:   0  


вообщем, всю голову сломал, не знаю как сделать(

http://trolltech.com/developer/faqs/faq.20...0-02.9810372345
написано что есть 3 способа:
1) передача эвентов
2) QCoreApplication::invokeLater()
3) и сигнал\слот с QueuedConnection

но к сожалению всё сказаное там для явы..

пробовал эвенты и через сигнал\слот с QueuedConnection.

пробовал даже вызывать метод в котором эмитится сигнал по которому вызывается нужный слот, как тут:
http://forum.sources.ru/index.php?showtopic=245838&hl=

результат один и тот же(


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


на ум приходит ещё один оч кривой способ..
отказаться от родителя в дочерних потоках и добавить в нужные методы moveToThread(this)
иии.. вот только что родилась идея ещё хуже.. пересылать данные по TCP на локалхост соединению между главным и дочерними потоками =)) бред..
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
ViGOur
  опции профиля:
сообщение 13.11.2008, 13:17
Сообщение #15


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

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

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




Репутация:   40  


Цитата(512es @ 13.11.2008, 12:27) *
не ужели никто не знает как вызывать метод из класса дочернего потока
Я знаю, но судя по обсуждению ты не понял, что и как делать, потому мне пример писать нужно, а времени пока увы нет. :(

Честно говоря там ничего сложного нет...
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
ViGOur
  опции профиля:
сообщение 13.11.2008, 14:30
Сообщение #16


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

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

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




Репутация:   40  


Вот я пример набросал, правда с рисованием, но думаю идея будет понятна... :)
Раскрывающийся текст
main.cpp
#include <QtCore/QCoreApplication>

#include "xThread.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    CxThread thread[2];
    for( int n=0; n < sizeof( thread)/sizeof( *thread); ++n)
    {
        thread[n].start();
    }

    while( true)
    {
        for( int n=0; n < sizeof( thread)/sizeof( *thread); ++n)
        {
            if( thread[n].isRunning())
                emit thread[n].drawText();
        }
        thread[0].sleep( 1);
        qDebug( "**********************");
    }

    return a.exec();
}

xThread.h
#ifndef XTHREAD_H
#define XTHREAD_H

#include <QThread>
#include <QMutex>

class CxPrint;

class CxThread : public QThread
{
    Q_OBJECT

private:
    static QMutex m_mutex;
    int        m_n;
    CxPrint *m_pPrint;

public:
    CxThread(QObject *parent=0);
    ~CxThread();

    void drawText();
    static void sleep ( unsigned long uls);
    int GetN()const { return m_n; }

protected:
    virtual void run();
    
};

class CxPrint: QObject
{
    Q_OBJECT

public:
    void drawText();

signals:
    void signalDrawText();

protected slots:
    void slotDraw();

public:
    CxPrint(void);
    virtual ~CxPrint(void);
};


#endif // XTHREAD_H

xThread.cpp
#include "xThread.h"
#include "xPrint.h"

QMutex CxThread::m_mutex;

CxThread::CxThread(QObject *parent)    : QThread(parent)
{
    m_n=0;
    m_pPrint = 0;
}

CxThread::~CxThread()
{
    delete m_pPrint;
    m_pPrint = 0;
}

void CxThread::drawText()
{
    if( m_pPrint)
        emit m_pPrint->drawText();
}

void CxThread::sleep ( unsigned long uls)
{
    QThread::sleep( uls);
}

void CxThread::run()
{
    {
        QMutexLocker locker(&m_mutex);
        static int n = 1;
        m_pPrint = new CxPrint;
        qDebug( "Runing thread with id: 0x%x, thread N: %d", QThread::currentThreadId(), n);
        m_n = n;
        n++;
    }

    CxThread::exec();
}

CxPrint::CxPrint(void)
{
    connect( this, SIGNAL( signalDrawText()), this, SLOT( slotDraw()));
}

CxPrint::~CxPrint(void)
{
}

void CxPrint::slotDraw()
{
    qDebug( "Draw in thread with id: 0x%x, thread N: %d", QThread::currentThreadId(), ((CxThread*)QThread::currentThread())->GetN());
}

void CxPrint::drawText()
{
    emit signalDrawText();
}


Сообщение отредактировал ViGOur - 13.11.2008, 14:31
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
512es
  опции профиля:
сообщение 13.11.2008, 16:42
Сообщение #17


Участник
**

Группа: Участник
Сообщений: 135
Регистрация: 31.10.2008
Пользователь №: 407

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




Репутация:   0  


ViGOur, спасибо!) то что надо!))
у меня рождалась мысль что объект надо создавать в секции run() но уже не верилось что это заработает..
вообще жудко запутаная конструкция получилось, жаль что нельзя упростить.. хотяя...
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
ViGOur
  опции профиля:
сообщение 13.11.2008, 18:01
Сообщение #18


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

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

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




Репутация:   40  


Цитата(512es @ 13.11.2008, 16:42) *
ViGOur, спасибо!) то что надо!))
Не за что, обращайся еще... ;)

Цитата(512es @ 13.11.2008, 16:42) *
жаль что нельзя упростить..
Можно.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
512es
  опции профиля:
сообщение 15.11.2008, 1:19
Сообщение #19


Участник
**

Группа: Участник
Сообщений: 135
Регистрация: 31.10.2008
Пользователь №: 407

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




Репутация:   0  


разве что от CxThread::drawText() удалось избавиться)

emit thread[n].drawText().m_pPrint.drawText()


вообще сервер работает быстро и надёжно) сколько бы не подключалось клиентов, пакеты им приходят моментально!)
отказался от эвентов, использую везде теперь только сигнал\слот =)
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 15.11.2008, 1:29
Сообщение #20


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9669
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

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




Репутация:   94  


Цитата(512es @ 15.11.2008, 4:19) *
вообще сервер работает быстро и надёжно) сколько бы не подключалось клиентов, пакеты им приходят моментально!)
Ну вот, а на пргорге тема о высоконагруженном сервере на Qt зашла в тупик (тык)
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

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


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




RSS Текстовая версия Сейчас: 10.5.2024, 22:26