Russian Qt Forum

Qt => Работа с сетью => Тема начата: GPPsoft от Январь 23, 2014, 10:53



Название: QTcoSocket прием данных в отдельном потоке.
Отправлено: GPPsoft от Январь 23, 2014, 10:53
Здравствуйте. Как сделать так, чтобы прием и обработка данных выполнялась в отдельном потоке? Спасибо!


Название: Re: QTcoSocket прием данных в отдельном потоке.
Отправлено: Fregloin от Январь 23, 2014, 11:38
Поиск в помощь.


Название: Re: QTcoSocket прием данных в отдельном потоке.
Отправлено: Serr500 от Январь 23, 2014, 11:38
1) Зачем? Сокеты в Qt асинхронные. Или нужны блокирующие операции?
2) Создаём потомка QThread, запускаем, создаём в нём сокеты, делаем moveToThread. С остальными потоками общаемся посредством сигналов.


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


Название: Re: QTcoSocket прием данных в отдельном потоке.
Отправлено: GPPsoft от Январь 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());
    }
}



Название: Re: QTcoSocket прием данных в отдельном потоке.
Отправлено: Serr500 от Январь 23, 2014, 11:50
Создаём потомка QThread, запускаем, создаём в нём сокеты, делаем moveToThread. С остальными потоками общаемся посредством сигналов.
Что из этого непонятно?


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


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


Название: Re: QTcoSocket прием данных в отдельном потоке.
Отправлено: GPPsoft от Январь 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?


Название: Re: QTcoSocket прием данных в отдельном потоке.
Отправлено: thechicho от Январь 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


Название: Re: QTcoSocket прием данных в отдельном потоке.
Отправлено: GPPsoft от Январь 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(из другого потока), ничего не происходит, даже ошибки нет. Данные тоже не отправляются. Просто тишина. В чем причина?


Название: Re: QTcoSocket прием данных в отдельном потоке.
Отправлено: thechicho от Январь 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);
}

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


Название: Re: QTcoSocket прием данных в отдельном потоке.
Отправлено: GPPsoft от Январь 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() вроде помог.


Название: Re: QTcoSocket прием данных в отдельном потоке.
Отправлено: GPPsoft от Январь 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. Что через сигнал, что через прямой вызов. Как быть?


Название: Re: QTcoSocket прием данных в отдельном потоке.
Отправлено: GPPsoft от Январь 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(), то поток продолжает работать... Как быть?


Название: Re: QTcoSocket прием данных в отдельном потоке.
Отправлено: GPPsoft от Январь 24, 2014, 10:05
Какие-то неудобные сокеты в Qt... Ощущение кривоты! Сделал вот так, но теперь непонятно как timeout сделать?

Код:
void TCPSocket::onReady()
{
    while(socket->bytesAvailable()){
        QByteArray data=socket->readAll();
        qDebug()<<"Данные";
    }
}

void TCPSocket::run(){
    connect(socket,SIGNAL(disconnected()),this,SLOT(_disconnected()));
    connect(socket,SIGNAL(readyRead()),this,SLOT(onReady()));
    exec();
}


Название: Re: QTcoSocket прием данных в отдельном потоке.
Отправлено: Fregloin от Январь 24, 2014, 11:07
неужели так трудно последовать моему совету и порыться в ветке связанной с сетью на форуме? там таких вопросов штук 5 минимум если не больше, и везде есть разъяснения. с конкретными примерами.


Название: Re: QTcoSocket прием данных в отдельном потоке.
Отправлено: GPPsoft от Январь 24, 2014, 11:33
неужели так трудно последовать моему совету и порыться в ветке связанной с сетью на форуме? там таких вопросов штук 5 минимум если не больше, и везде есть разъяснения. с конкретными примерами.
Вы не поверите. Я уже 2 дня сижу над этим вопросом. И гуглил и искал. Я не нашел решения моей проблемы! :(


Название: Re: QTcoSocket прием данных в отдельном потоке.
Отправлено: Kurles от Январь 24, 2014, 11:46
Какие-то неудобные сокеты в Qt... Ощущение кривоты! Сделал вот так, но теперь непонятно как timeout сделать?
Вы просто не умеете их готовить ) А для таймаутов есть QTimer


Название: Re: QTcoSocket прием данных в отдельном потоке.
Отправлено: kuzulis от Январь 24, 2014, 12:11
GPPsoft,

покамест все неправильно. Читай документацию, смотри пимеры, гугли, работай. А то развелось халявщихов, которые хотят все получить с наскоку, сразу. :)


Название: Re: QTcoSocket прием данных в отдельном потоке.
Отправлено: GPPsoft от Январь 25, 2014, 03:41
GPPsoft,

покамест все неправильно. Читай документацию, смотри пимеры, гугли, работай. А то развелось халявщихов, которые хотят все получить с наскоку, сразу. :)

А так?

Код
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,SLOT(onDisconnect()));
   socket->connectToHost(hostName, port);
 
   if (!socket->waitForConnected(5000)) {
       emit error(socket->errorString());
       return false;
   }else{
       if(!isRunning())
           start();
       return true;
   }
}
 
void TCPSocket::killConnection(){
   socket->disconnectFromHost();
}
 
void TCPSocket::sendData(const QByteArray &packet){
   socket->write(packet,packet.length());
   socket->flush();
}
 
void TCPSocket::onDataReceive()
{
   while(socket->bytesAvailable()){
       QByteArray data=socket->readAll();
       qDebug()<<"Данные";
   }
}
 
void TCPSocket::onDisconnect(){
   emit disconnected();
   exit(0);
}
 
void TCPSocket::run(){
   QTcpSocket tcpSocket;
   connect(&tcpSocket,SIGNAL(readyRead()), this, SLOT(onDataReceive()));
   if (!tcpSocket.setSocketDescriptor(socket->socketDescriptor())) {
       emit error(tcpSocket.errorString());
       return;
   }
   exec();
}
 

Нихрена прием данных не работает теперь.. Ну и гемморой в Qt с сокетами. Ужас!


Название: Re: QTcoSocket прием данных в отдельном потоке.
Отправлено: GPPsoft от Январь 25, 2014, 10:05
В продолжение геммороя. Сделал по "феншую", все через сигналы и слоты. Теперь при отправке данных через сигнал славливаю все те же
QSocketNotifier: socket notifiers cannot be enabled from another thread
QSocketNotifier: socket notifiers cannot be disabled from another thread


.h GUI

Код
C++ (Qt)
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
 
#include <QMainWindow>
#include <tcpsocket.h>
//#include <hubsession.h>
 
namespace Ui {
class MainWindow;
}
 
class MainWindow : public QMainWindow
{
   Q_OBJECT
 
public:
   explicit MainWindow(QWidget *parent = 0);
   ~MainWindow();
signals:
   void sendData(const QByteArray &packet);
private slots:
   void on_connectButton_clicked();
   void on_sendButton_clicked();
   void disconnected();
   void connected();
   void error(QString error);
   void on_pushButton_clicked();
private:
   Ui::MainWindow *ui;
   TCPSocket *socket;
};
 
#endif // MAINWINDOW_H
 

.cpp GUI
Код
C++ (Qt)
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "QMessageBox"
 
MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{
   ui->setupUi(this);
   socket = new TCPSocket();
 
   connect(socket,SIGNAL(connected()),this,SLOT(connected()));
   connect(socket,SIGNAL(disconnected()),this,SLOT(disconnected()));
   connect(socket,SIGNAL(error(QString)),this,SLOT(error(QString)));
   connect(this,SIGNAL(sendData(QByteArray)),socket,SLOT(sendData(QByteArray)));
}
 
void MainWindow::disconnected(){
   QMessageBox::information(this,"Внимание","Отключились");
}
 
void MainWindow::connected(){
   QMessageBox::information(this,"Внимание","Подключились!");
}
 
void MainWindow::error(QString error){
   QMessageBox::information(this,"Внимание",error);
}
 
MainWindow::~MainWindow()
{
   delete ui;
}
 
void MainWindow::on_connectButton_clicked()
{
  socket->connectTo("192.168.0.3",3478);
}
 
void MainWindow::on_sendButton_clicked()
{
  emit sendData(ui->textToSend->toPlainText().toUtf8().data());
}
 
void MainWindow::on_pushButton_clicked()
{
   socket->killConnection();
}
 

.h TCPSocket
Код
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 killConnection();
private:
   QTcpSocket *socket;
   QString hostName;
   int port;
private slots:
   void onDataReceive();
   void onDisconnect();
public slots:
   void sendData(const QByteArray &packet);
signals:
 void disconnected();
 void connected();
 void error(QString error);
};
 
#endif // TCPSOCKET_H
 

.cpp TCPSocket
Код
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::killConnection(){
   socket->disconnectFromHost();
}
 
void TCPSocket::sendData(const QByteArray &packet){
   socket->write(packet,packet.length());
   socket->flush();
}
 
void TCPSocket::onDataReceive()
{
   while(socket->bytesAvailable()){
       QByteArray data=socket->readAll();
       qDebug()<<"Данные";
   }
}
 
void TCPSocket::onDisconnect(){
   emit disconnected();
   exit(0);
}
 
void TCPSocket::run(){
 
   socket = new QTcpSocket();
   connect(socket,SIGNAL(readyRead()),this,SLOT(onDataReceive()));
   connect(socket,SIGNAL(disconnected()),this,SLOT(onDisconnect()));
   socket->connectToHost(hostName, port);
 
   if (!socket->waitForConnected(5000)) {
       emit error(socket->errorString());
       return;
   }
 
   emit connected();
 
   exec();
}
 

Что я делаю не так?! Уже перерыл кучу информации и в google и тут на форуме. Сижу 3 день! Подскажите кто-нибудь, я готов уже заплатить за подсказку. Как мне сделать так, чтобы прием и обработка данных были в отдельном потоке а отправку отключение и подключение к хосту я мог делать в потоке GUI? Спасибо!


Название: Re: QTcoSocket прием данных в отдельном потоке.
Отправлено: Old от Январь 25, 2014, 10:46
Про невозможность отключения нотифиера сообщение, как я вижу, выдается при попытке отключиться?
А в какой момент получаете сообщение о невозможности включения нотификатора?


Название: Re: QTcoSocket прием данных в отдельном потоке.
Отправлено: GPPsoft от Январь 25, 2014, 11:07
Про невозможность отключения нотифиера сообщение, как я вижу, выдается при попытке отключиться?
А в какой момент получаете сообщение о невозможности включения нотификатора?
При вызове TCPSocket::sendData. Не важно напрямую вызывать или через сигнал. Одна и та же ошибка в логи сваливается.


Название: Re: QTcoSocket прием данных в отдельном потоке.
Отправлено: Old от Январь 25, 2014, 11:13
При вызове TCPSocket::sendData. Не важно напрямую вызывать или через сигнал. Одна и та же ошибка в логи сваливается.
Ага точно - увидал. :)
Все работает так, как вы написали. Не сердитесь, но вам нужно получше разобраться именно в поддержке ниток в Qt.
На форуме очень много раз поднималась эта тема, совсем недавно я пытался на пальцах это рассказать в очередной раз - поищите.
Смысл в неправильных типах connect, которые Qt не может корректно определить, в виду того что все соединяемые объекты находятся в контексте одной нитки.


Название: Re: QTcoSocket прием данных в отдельном потоке.
Отправлено: GPPsoft от Январь 25, 2014, 11:19
При вызове TCPSocket::sendData. Не важно напрямую вызывать или через сигнал. Одна и та же ошибка в логи сваливается.
Ага точно - увидал. :)
Все работает так, как вы написали. Не сердитесь, но вам нужно получше разобраться именно в поддержке ниток в Qt.
На форуме очень много раз поднималась эта тема, совсем недавно я пытался на пальцах это рассказать в очередной раз - поищите.
Смысл в неправильных типах connect, которые Qt не может корректно определить, в виду того что все соединяемые объекты находятся в контексте одной нитки.
Что делать и как быть? Нужно решение здесь и сейчас. К сожалению пока нет времени вникать особо глубоко. Портирую один свой довольно большой проект. Уже к сожалению подумываю о связке java + JNI. Очень странно что на мой субъективный взгляд работа с сокетами так криво реализована в данном фреймворке. Считаю что получение данных обязательно должно быть в отдельном потоке... Как я понимаю в Qt классы для работы с сокетами по умолчанию асинхронные. Вообщем уже в 10 наверное раз пытаюсь попробовать Qt "на вкус" и все как-то чаще на "горечь" наталкиваюсь. Очень жаль. Но альтернатив почти нет.


Название: Re: QTcoSocket прием данных в отдельном потоке.
Отправлено: GPPsoft от Январь 25, 2014, 11:21
Самое интересное что программа не падает и даже отправляет пакет, но не правильно все это как-то. В логах должно быть чисто :)


Название: Re: QTcoSocket прием данных в отдельном потоке.
Отправлено: Old от Январь 25, 2014, 11:21
Что делать и как быть? Нужно решение здесь и сейчас.
Код
C++ (Qt)
TCPSocket::TCPSocket(QObject *parent) :QThread(parent)
{
   moveToThread( this );
}
 


Название: Re: QTcoSocket прием данных в отдельном потоке.
Отправлено: Old от Январь 25, 2014, 11:22
Очень странно что на мой субъективный взгляд работа с сокетами так криво реализована в данном фреймворке.
Просто вы с ним не очень разобрались. ;)

Но для серьезных применений тоже QtNetwork не использую, предпочитаю boost asio.


Название: Re: QTcoSocket прием данных в отдельном потоке.
Отправлено: GPPsoft от Январь 25, 2014, 11:26
Что делать и как быть? Нужно решение здесь и сейчас.
Код
C++ (Qt)
TCPSocket::TCPSocket(QObject *parent) :QThread(parent)
{
   moveToThread( this );
}
 


:) Это что за кривота? Зачем поток в себя же запихивать?! :o


Название: Re: QTcoSocket прием данных в отдельном потоке.
Отправлено: Old от Январь 25, 2014, 11:27
:) Это что за кривота? Зачем поток в себя же запихивать?! :o
Это запись означает, что нужно объект QThread перенести из контекста нитки его создавшей в контекст нитки этого объекта. :)

Если пересмотреть архитектуру, то таких вещей делать не придется, но для этого надо вникать. :)


Название: Re: QTcoSocket прием данных в отдельном потоке.
Отправлено: GPPsoft от Январь 25, 2014, 11:31
:) Это что за кривота? Зачем поток в себя же запихивать?! :o
Это запись означает, что нужно объект QThread перенести из контекста нитки его создавшей в контекст нитки этого объекта. :)

Если пересмотреть архитектуру, то таких вещей делать не придется, но для этого надо вникать. :)

А что тут пересматривать? Все же просто. Надо чтобы чтение данных было в отдельном потоке, а работа с сокетом в любом потоке.


Название: Re: QTcoSocket прием данных в отдельном потоке.
Отправлено: Old от Январь 25, 2014, 11:44
А что тут пересматривать? Все же просто. Надо чтобы чтение данных было в отдельном потоке, а работа с сокетом в любом потоке.
Например, сделать объект обработчик, который будет взаимодействовать с сокетом и уже эту связку помещать в отдельную нитку. Тогда не придется наследоваться не от сокета, не от нитки.


Название: Re: QTcoSocket прием данных в отдельном потоке.
Отправлено: GPPsoft от Январь 25, 2014, 11:50
А что тут пересматривать? Все же просто. Надо чтобы чтение данных было в отдельном потоке, а работа с сокетом в любом потоке.
Например, сделать объект обработчик, который будет взаимодействовать с сокетом и уже эту связку помещать в отдельную нитку. Тогда не придется наследоваться не от сокета, не от нитки.
Т.е обернуть работу с сокетом в класс и запустить его в отдельном потоке? А как же мне тогда из GUI дергать за методы? Ведь та же самая проблема будет.


Название: Re: QTcoSocket прием данных в отдельном потоке.
Отправлено: GPPsoft от Январь 25, 2014, 11:58
Постараюсь описать то чего я хочу добиться. Хочу написать некий класс Session который будет работать с сокетом.
Класс должен:
1. Иметь конструктор Session(const QTcpSocket), либо метод setClientSocket(const QTcpSocket)
2. Читать данные в отдельном потоке
3. Иметь метод отключения, аля disconnectFromHost(потокобезопасный)
4. Испускать служебные сигналы(сигнал отключения от хоста и т.д)

Далее я наследуюсь этого класса и расширяю его функционал, в зависимости от предназначения.


Название: Re: QTcoSocket прием данных в отдельном потоке.
Отправлено: Old от Январь 25, 2014, 12:01
Лучше смотреть на саму задачу... что должен этот класс Session делать?


Название: Re: QTcoSocket прием данных в отдельном потоке.
Отправлено: GPPsoft от Январь 25, 2014, 12:04
Лучше смотреть на саму задачу... что должен этот класс Session делать?

Принимать в качестве параметра конструктора или через метод объект сокета и обрабатывать приходящие данные в отдельном потоке. Могу показать реализацию подобного класса на java. Собственно я и хочу повторить его. Сейчас приведу пример.


Название: Re: QTcoSocket прием данных в отдельном потоке.
Отправлено: Old от Январь 25, 2014, 12:06
Принимать в качестве параметра конструктора или через метод объект сокета и обрабатывать приходящие данные в отдельном потоке. Могу показать реализацию подобного класса на java. Собственно я и хочу повторить его. Сейчас приведу пример.
Не надо яву. :)
Абстрагируйтесь от конструкторов и параметров, что нужно сделать. :)
 


Название: Re: QTcoSocket прием данных в отдельном потоке.
Отправлено: GPPsoft от Январь 25, 2014, 12:08
Максимально упростил. Оставил только ключевые моменты.
Код
Java
public abstract class Session {
 
public static final int BUFFER_SIZE=8192*2;
public static final int ALIVE_TIMEOUT = 60000;
 
private Socket mClient=null;
 
public void killSession() {
if (mClient != null){
try {
this.mClient.close();
} catch (IOException e) {
e.printStackTrace();
}
               }
}
 
public void setClientSocket(Socket client) throws IOException{
 
if(this.mClient!=null){
mClient.close();
}
 
this.mClient=client;
 
mAliveTimer= new Timer("ALIVE_TIMER");
mAliveTimer.schedule(new TimerTask() {
public void run() {
sendData(new Packets.KeepAlive());
}
},ALIVE_TIMEOUT,ALIVE_TIMEOUT);
 
new Thread(new ClientDataRead(),"CLIENT_THREAD").start();
}
 
protected synchronized boolean sendData(byte[] data){
if(mClient!=null){
try{
mClient.getOutputStream().write(data);
}
catch(Exception ex){
return false;
}
return true;
}else{
return false;
}
}
 
protected abstract void disconnect();
 
public class ClientDataRead implements Runnable{
 
public void run(){
try{  
int receivedBytes;
               byte[] dataBuffer = new byte[BUFFER_SIZE];
 
               while ((receivedBytes = stream.read(dataBuffer, 0, dataBuffer.length)) != -1) {
             //Тут я обрабатываю данные....
               }
 
disconnect();
}
catch(Exception ex)
{
ex.printStackTrace();
mAliveTimer.cancel();
disconnect();
}
finally
{
try {
mClient=null;
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
 


Название: Re: QTcoSocket прием данных в отдельном потоке.
Отправлено: GPPsoft от Январь 25, 2014, 12:10
Принимать в качестве параметра конструктора или через метод объект сокета и обрабатывать приходящие данные в отдельном потоке. Могу показать реализацию подобного класса на java. Собственно я и хочу повторить его. Сейчас приведу пример.
Не надо яву. :)
Абстрагируйтесь от конструкторов и параметров, что нужно сделать. :)
Думаю проще кодом объяснить. В приведенном примере обработка данных происходит в отдельном потоке. Остальная работа с классом сокета - "потоконезависима".


Название: Re: QTcoSocket прием данных в отдельном потоке.
Отправлено: Old от Январь 25, 2014, 12:13
Думаю проще кодом объяснить. В приведенном примере обработка данных происходит в отдельном потоке. Остальная работа с классом сокета - "потоконезависима".
Сейчас нужно уехать, чуть позже... :)


Название: Re: QTcoSocket прием данных в отдельном потоке.
Отправлено: GPPsoft от Январь 25, 2014, 12:17
Думаю проще кодом объяснить. В приведенном примере обработка данных происходит в отдельном потоке. Остальная работа с классом сокета - "потоконезависима".
Сейчас нужно уехать, чуть позже... :)
Вообщем все что мне нужно, это повторить класс Session который я реализовал на java.

P.S: Буду ждать! Спасибо за проявленный интерес ;)


Название: Re: QTcoSocket прием данных в отдельном потоке.
Отправлено: Old от Январь 25, 2014, 14:30
Вообщем все что мне нужно, это повторить класс Session который я реализовал на java.
Тогда вы его уже практически повторили, осталось отвязать прямой вызов killConnection (использовать сигналы).

Другой вариант, это сделать через воркер (обработчик трафика), примерно так:
Код
C++ (Qt)
QThread *th = new QThread;
 
QTcpSocket *sock = new QTcpSocket;
sock->moveToThread( th );
 
Worker *w = new Worker;
w->moveToThread( th );
 
// Подключаем нужные сигналы между сокетом и работалкой.
connect( sock, ..., w ... );
connect( sock, ..., w ... );
 
th->start();
 

Или можно оформить весь процесс работы в одной функции и использовать QtConcurent, для запуска их в разных нитках.



Название: Re: QTcoSocket прием данных в отдельном потоке.
Отправлено: GPPsoft от Февраль 05, 2014, 07:05
Вообщем все что мне нужно, это повторить класс Session который я реализовал на java.
Тогда вы его уже практически повторили, осталось отвязать прямой вызов killConnection (использовать сигналы).

Другой вариант, это сделать через воркер (обработчик трафика), примерно так:
Код
C++ (Qt)
QThread *th = new QThread;
 
QTcpSocket *sock = new QTcpSocket;
sock->moveToThread( th );
 
Worker *w = new Worker;
w->moveToThread( th );
 
// Подключаем нужные сигналы между сокетом и работалкой.
connect( sock, ..., w ... );
connect( sock, ..., w ... );
 
th->start();
 

Или можно оформить весь процесс работы в одной функции и использовать QtConcurent, для запуска их в разных нитках.

Т.е как я понимаю Worker это мой класс который должен обрабатывать входящий трафик? И в данном примере он будет обрабатывать все сигналы от сокета в отдельном потоке?