Russian Qt Forum
Ноябрь 23, 2024, 08:28 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2 3   Вниз
  Печать  
Автор Тема: QTcoSocket прием данных в отдельном потоке.  (Прочитано 22099 раз)
GPPsoft
Гость
« : Январь 23, 2014, 10:53 »

Здравствуйте. Как сделать так, чтобы прием и обработка данных выполнялась в отдельном потоке? Спасибо!
Записан
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« Ответ #1 : Январь 23, 2014, 11:38 »

Поиск в помощь.
Записан
Serr500
Гость
« Ответ #2 : Январь 23, 2014, 11:38 »

1) Зачем? Сокеты в Qt асинхронные. Или нужны блокирующие операции?
2) Создаём потомка QThread, запускаем, создаём в нём сокеты, делаем moveToThread. С остальными потоками общаемся посредством сигналов.
Записан
GPPsoft
Гость
« Ответ #3 : Январь 23, 2014, 11:45 »

1) Зачем? Сокеты в Qt асинхронные. Или нужны блокирующие операции?
2) Создаём потомка QThread, запускаем, создаём в нём сокеты, делаем moveToThread. С остальными потоками общаемся посредством сигналов.
Ну сокет принимает данные и обрабатывает их.... При этом окно зависает. Так не должно быть! Мне надо чтобы я из основного потока мог подключаться-отключаться, а данные которые принимает сокет обрабатывались в отдельном потоке.
Записан
GPPsoft
Гость
« Ответ #4 : Январь 23, 2014, 11:48 »

Код:
connect(this->tcpSocket,SIGNAL(readyRead()),this,SLOT(receiveData()));
.....................................................

//ЭТО НУЖНО В ОТДЕЛЬНЫЙ ПОТОК!
void Session::receiveData()
{
    while(tcpSocket->bytesAvailable())
    {
        QByteArray data=tcpSocket->readAll();
        packetSplitter.setByteArray(&data,data.length());
    }
}

Записан
Serr500
Гость
« Ответ #5 : Январь 23, 2014, 11:50 »

Создаём потомка QThread, запускаем, создаём в нём сокеты, делаем moveToThread. С остальными потоками общаемся посредством сигналов.
Что из этого непонятно?
Записан
GPPsoft
Гость
« Ответ #6 : Январь 23, 2014, 11:52 »

Создаём потомка QThread, запускаем, создаём в нём сокеты, делаем moveToThread. С остальными потоками общаемся посредством сигналов.
Что из этого непонятно?
Буду очень благодарен, если вы покажите пример или дадите ссылку на хороший. Спасибо!
Записан
GPPsoft
Гость
« Ответ #7 : Январь 23, 2014, 12:52 »

Ок. Как теперь послать сигнал моему объекту который запустил у себя сокет в отдельном потоке. Вообще как-то не логично и спаггетикодово. Если в java и C# я просто запускал в отдельном потоке чтение потока с сокета, то тут какие-то непонятные наследования и т.д.. Почему так сложно?
Записан
GPPsoft
Гость
« Ответ #8 : Январь 23, 2014, 12:55 »

Запустил в отдельном потоке вот так. Но как понять когда поток завершиться?

Код:
void Session::setClienSocket(QTcpSocket &socket)
{
    this->tcpSocket=&socket;
    QThread* thread = new QThread;
    this->tcpSocket->moveToThread(thread);
    connect(thread, SIGNAL(started()), this, SLOT(startSocket()));
    thread->start(QThread::HighestPriority);
}

void Session::startSocket()
{
    packetSplitter.setEncryptor(packetEncryptor);
    connect(&packetSplitter,SIGNAL(onPacket(QByteArray*)),this,SLOT(onPacket(QByteArray*)));
    connect(this->tcpSocket,SIGNAL(disconnected()),this,SIGNAL(disconnect()));
    connect(this->tcpSocket,SIGNAL(readyRead()),this,SLOT(receiveData()));
}

Еще у меня есть метод:
Код:
void Session::sendData(const QByteArray &packet)
{
..............................................................
    tcpSocket->write(data);
}
Тут я славливаю "socket notifiers cannot be enabled from another thread". оно и понятно. Но как мне теперь вызывать этот метод из потока GUI?
Записан
thechicho
Гость
« Ответ #9 : Январь 23, 2014, 13:58 »

можно сделать отдельный класс для работы с сокетом. поместить объект этого класса в отдельный поток. если нужны данные для обработки в главном потоке, передавать их туда сигналом.

Код:
QThread *thread = new QThread;
Worker *worker = new Worker;
worker->moveToThread(thread);
thread->start();

http://qt-project.org/doc/qt-4.8/qthread.html
Записан
GPPsoft
Гость
« Ответ #10 : Январь 23, 2014, 14:43 »

Пошел таким путем:

.h
Код
C++ (Qt)
#ifndef TCPSOCKET_H
#define TCPSOCKET_H
 
#include <QThread>
#include <QtNetwork>
 
typedef unsigned char BYTE;
 
class TCPSocket : public QThread
{
   Q_OBJECT
public:
   TCPSocket(QObject *parent = 0);
 
   void run();
   void connectTo(QString hostName, int port);
   void sendData(const QByteArray &packet);
private:
   QTcpSocket *socket;
   QString hostName;
   int port;
signals:
 void connected();
 void disconnected();
 void notConnected();
public slots:
 
};
 
#endif // TCPSOCKET_H
 

.cpp
Код
C++ (Qt)
#include "tcpsocket.h"
 
TCPSocket::TCPSocket(QObject *parent) :QThread(parent)
{
}
 
void TCPSocket::connectTo(QString hostName, int port)
{
   this->hostName=hostName;
   this->port=port;
 
   if(!isRunning())
       start();
}
 
void TCPSocket::sendData(const QByteArray &packet)
{
   socket->write(packet);
}
 
void TCPSocket::run()
{
   QString serverName = hostName;
   int serverPort = port;
 
   socket = new QTcpSocket();
   socket->connectToHost(serverName, serverPort);
 
   if (!socket->waitForConnected(5000)) {
       emit notConnected();
       return;
   }
 
   emit connected();
 
   while(socket->waitForReadyRead(60000)){
       while(socket->bytesAvailable())
       {
           QByteArray data=socket->readAll();
           qDebug()<<"Данные";
       }
   }
 
   emit disconnected();
}
 

При отправке данных, т.е при вызове TCPSocket::sendData(из другого потока), ничего не происходит, даже ошибки нет. Данные тоже не отправляются. Просто тишина. В чем причина?
« Последнее редактирование: Январь 23, 2014, 14:48 от GPPsoft » Записан
thechicho
Гость
« Ответ #11 : Январь 23, 2014, 19:09 »

TCPSocket *tCPSocket = new TCPSocket ;
connect(this, SIGNAL(sendData(QByteArray)), tCPSocket, SLOT(sendData(QByteArray)));

QByteArray data;
emit sendData(data);

class Session
{
signals:
    void sendData(QByteArray);

};

class TCPSocket : public QThread
{
public slots:
    void sendData(QByteArray);
}

так попробуйте
« Последнее редактирование: Январь 23, 2014, 19:11 от thechicho » Записан
GPPsoft
Гость
« Ответ #12 : Январь 24, 2014, 03:21 »

TCPSocket *tCPSocket = new TCPSocket ;
connect(this, SIGNAL(sendData(QByteArray)), tCPSocket, SLOT(sendData(QByteArray)));

QByteArray data;
emit sendData(data);

class Session
{
signals:
    void sendData(QByteArray);

};

class TCPSocket : public QThread
{
public slots:
    void sendData(QByteArray);
}

так попробуйте

Не работает. Слот вызывается... socket->write(packet) выполняется. Но данные на том конце не приходят. Тишина в эфире. socket->flush() вроде помог.
« Последнее редактирование: Январь 24, 2014, 03:24 от GPPsoft » Записан
GPPsoft
Гость
« Ответ #13 : Январь 24, 2014, 03:38 »

Код
C++ (Qt)
void TCPSocket::sendData(const QByteArray &packet)
{
   socket->write(packet,packet.length());
   socket->flush();
}
 
На socket->flush() ловлю QSocketNotifier: socket notifiers cannot be disabled from another thread. Что через сигнал, что через прямой вызов. Как быть?
Записан
GPPsoft
Гость
« Ответ #14 : Январь 24, 2014, 05:56 »

Вот что получилось, вроде то что нужно, но...

.h
Код
C++ (Qt)
#ifndef TCPSOCKET_H
#define TCPSOCKET_H
 
#include <QThread>
#include <QtNetwork>
 
typedef unsigned char BYTE;
 
class TCPSocket : public QThread
{
   Q_OBJECT
public:
   TCPSocket(QObject *parent = 0);
   void run();
   bool connectTo(QString hostName, int port);
   void sendData(const QByteArray &packet);
   void killConnection();
private:
   QTcpSocket *socket;
signals:
 void disconnected();
 void error(QString error);
};
 
#endif // TCPSOCKET_H
 

.cpp
Код
C++ (Qt)
#include "tcpsocket.h"
 
TCPSocket::TCPSocket(QObject *parent) :QThread(parent)
{
}
 
bool TCPSocket::connectTo(QString hostName, int port)
{
   socket = new QTcpSocket();
   connect(socket,SIGNAL(disconnected()),this,SIGNAL(disconnected()));
   socket->connectToHost(hostName, port);
 
   if (!socket->waitForConnected(5000)) {
       emit error(socket->errorString());
       return false;
   }else{
       if(!isRunning())
           start();
       return true;
   }
}
 
void TCPSocket::sendData(const QByteArray &packet)
{
   socket->write(packet,packet.length());
   socket->flush();
}
 
void TCPSocket::killConnection(){
   socket->disconnectFromHost();
}
 
void TCPSocket::run()
{
   QTcpSocket socketReceiver;
   connect(&socketReceiver,SIGNAL(disconnected()),this,SIGNAL(disconnected()));
   socketReceiver.setSocketDescriptor(socket->socketDescriptor());
 
   while(socketReceiver.waitForReadyRead(5000)){
       while(socketReceiver.bytesAvailable())
       {
           QByteArray data=socketReceiver.readAll();
           qDebug()<<"Данные";
       }
   }
 
   emit error(socketReceiver.errorString());
}
 

Насколько это правильно? И какие могут быть проблемы при таком раскладе?

Нашел проблему одну проблему. Если вызвать killConnection(), то поток продолжает работать... Как быть?
« Последнее редактирование: Январь 24, 2014, 07:33 от GPPsoft » Записан
Страниц: [1] 2 3   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.194 секунд. Запросов: 23.