Russian Qt Forum

Qt => Общие вопросы => Тема начата: GPPsoft от Декабрь 22, 2013, 08:51



Название: QTCPSocket в отдельном потоке.
Отправлено: GPPsoft от Декабрь 22, 2013, 08:51
Здравствуйте. Как правильно заставить QTCPSocket принимать и обрабатывать данные в отдельном потоке? Сейчас у меня сделано так:
Код:
connect(tcpSocket,SIGNAL(connected()),this,SLOT(on_connected()));
connect(tcpSocket,SIGNAL(disconnected()),this,SLOT(on_disconnected()));
connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(on_data()));

Три сигнала... первые два меня устраивают в плане того что ни выполняются в потоке UI, но вот получение и обработка данных необходима в отдельном потоке. Как реализовать? Как я понимаю сейчас данные обрабатываются в UI потоке.
Код:
void MainWindow::on_data()
{
    while(tcpSocket->bytesAvailable())
    {
        QByteArray data=tcpSocket->readAll();
        packetSplitter->setByteArray(&data,data.length());
    }
}

Спасибо!


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: Bepec от Декабрь 22, 2013, 11:53
Читаем про QThread.

Есть два способа.
1) создать класс с нужным вам функционалом, создать новый поток(QThread) и перенести его (moveToThread) в отдельный поток.

2) создать наследника от QThread и в нём в конструкторе сделать moveToThread(this). И в этом наследнике творите что хотите.

Оба способа равнозначны, единственно что в первом можно будет разделять поток и класс(отдельные сущности),а во втором они будут единым целом.

PS мне больше нравится второй из-за экономии сущностей. Задач по перебросам из потока в поток, для которых необходим первый способ мне ещё не встречалось.


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: Nidxogg от Январь 14, 2014, 21:46
Читаем про QThread.
Есть два способа.
1) создать класс с нужным вам функционалом, создать новый поток(QThread) и перенести его (moveToThread) в отдельный поток.

2) создать наследника от QThread и в нём в конструкторе сделать moveToThread(this). И в этом наследнике творите что хотите.

Оба способа равнозначны, единственно что в первом можно будет разделять поток и класс(отдельные сущности),а во втором они будут единым целом.

PS мне больше нравится второй из-за экономии сущностей. Задач по перебросам из потока в поток, для которых необходим первый способ мне ещё не встречалось.
Несколько вопросов:
1)А можете показать, где в документации на QThread это написано? (про moveToThread)
2)По второму способу. Если без moveToThread вывести в контруктуре gui-класса и конструкторе наследника QThread 
Код:
qDebug()<<this->thread() 
- адреса одинаковые. Это потому что поток создан в объекте gui-класса? Или не так надо смотреть в каком потоке живет объект?
Если смотреть через
Цитировать
qDebug()<<QThread::currentThread();
, то разные

Вообщем запутался ???





Название: Re: QTCPSocket в отдельном потоке.
Отправлено: Bepec от Январь 14, 2014, 22:14
QThread - myThread;
До запуска потока
Код:
myThread.start()
всё живёт в потоке родителя.
После
Код:
myThread.start()
инициализируется поток, и метод run() начинает выполнятся в новом потоке.
moveToThread(this) в конструкторе переносит весь myThread в него самого :D Это интересный момент.
И после
Код:
myThread.start()
все слоты/методы будут вызываться в новом потоке.

В каком же потоке вызываться будет слот, зависит от типа соединения. Это тоже отдельная песня :)

PS Я сам доходил до этого неделю, если не больше. Интернета не было, потому исписывал бумажку :D


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: Nidxogg от Январь 14, 2014, 22:18
Цитировать
инициализируется поток, и метод run() начинает выполнятся в новом потоке.
зачем тогда moveToThread(this), если добились "желаемого?"


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: Old от Январь 14, 2014, 22:25
зачем тогда moveToThread(this), если добились "желаемого?"
Тут цель не в этом.
Стоит сразу отметить, что все потоки выполняются в одном адресном пространстве и реально никаких контекстов нет.
Их искусственно вводи Qt, что бы у него была возможность решать какой тип соединения connect использовать в том или ином случае, при испускании сигнала.
Т.е. если два объекта порожденных от QObject, находятся в одном контексте, то будет использоваться DirectConnect (прямой вызов метода), если в разных - QueueConnect (вызов через очередь событий нити получателя).


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: Bepec от Январь 14, 2014, 22:26
Если не сделать moveToThread, то все прочие методы наследника от QThread будут выполняться в потоке родителя.
run - всегда в новом. Прочие - после moveToThread.


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: Old от Январь 14, 2014, 22:30
Да, и про moveToThread забыл написать... :)

При конструировании Q-объекта он начинает принадлежать контексту той нити в которой создан, а moveToThread перемещает этот объект в контекст указанной нити.


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: Nidxogg от Январь 15, 2014, 06:18
Спасибо


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: stix357 от Декабрь 20, 2016, 08:05
QThread - myThread;
До запуска потока
Код:
myThread.start()
всё живёт в потоке родителя.
После
Код:
myThread.start()
инициализируется поток, и метод run() начинает выполнятся в новом потоке.
moveToThread(this) в конструкторе переносит весь myThread в него самого :D Это интересный момент.
И после
Код:
myThread.start()
все слоты/методы будут вызываться в новом потоке.

В каком же потоке вызываться будет слот, зависит от типа соединения. Это тоже отдельная песня :)

PS Я сам доходил до этого неделю, если не больше. Интернета не было, потому исписывал бумажку :D
Мммм, попробую поднять тему.
Предложенные варианты:
Цитировать
Есть два способа.
1) создать класс с нужным вам функционалом, создать новый поток(QThread) и перенести его (moveToThread) в отдельный поток.

2) создать наследника от QThread и в нём в конструкторе сделать moveToThread(this). И в этом наследнике творите что хотите.

Оба способа равнозначны, единственно что в первом можно будет разделять поток и класс(отдельные сущности),а во втором они будут единым целом.

PS мне больше нравится второй из-за экономии сущностей. Задач по перебросам из потока в поток, для которых необходим первый способ мне ещё не встречалось.
Вариант 1- работает, но странно:
Код:
TCPClientQt::TCPClientQt(): QTcpSocket()
.....
m_pTcpSocket = new QTcpSocket(this);

отрабатываются сигналы
Код:
 connect(m_pTcpSocket, SIGNAL(connected()), SLOT(slotConnected()));
 connect(m_pTcpSocket, SIGNAL(disconnected()), SLOT(slotDisconnected()));
 connect(m_pTcpSocket, SIGNAL(readyRead()), SLOT(slotReadyRead()));

не отрабатывают
Код:
 connect(m_pTcpSocket, SIGNAL(error(QAbstractSocket::SocketError)),this, SLOT(slotError(QAbstractSocket::SocketError)));
 connect(m_pTcpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState socketState )),this, SLOT(slotStateChanged(QAbstractSocket::SocketState)));

Вариант 2 - не работает на Win7-32, Qt-4.8.1
Сокет запускается в основном потоке. Гуй виснет. При получении сокетом пакета.

Вариант 3 - создание наследника QTcpSocket в наследнике QThread в методе run() согласно рекомендациям Шлее
Код:
ReadData::ReadData(QObject *parent) :
    QThread(parent)
.....
void ReadData::run()
{
    try
    {

      m_Client=new TCPClientQt(this);
      exec();
    }catch(const std::exception& ex)
    {
        m_Result=-2;
    }
 }
работает аналогично варианту 1.

В чем мой косяк?


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: Bepec от Декабрь 20, 2016, 11:55
1) вы создали TCPSocket и указали ему родителя. И будет он жить теперь в потоке родителя (this). Перенос в поток вы не осуществили.
1*) отработка сигналов должна работать в любом случае, видимо вы где то ошиблись, что без полного кода проекта сказать невозможно.
2) Хз что вы там наделали, но явно всё неправильно. Приводите код, а не "я сделал, оно не работает, способ плохо, код не покажу, я идеален" :D
3) Опять таки нет полного кода :D Ничего сказать не могу.


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: stix357 от Декабрь 20, 2016, 12:14
1) вы создали TCPSocket и указали ему родителя. И будет он жить теперь в потоке родителя (this). Перенос в поток вы не осуществили.
1*) отработка сигналов должна работать в любом случае, видимо вы где то ошиблись, что без полного кода проекта сказать невозможно.
2) Хз что вы там наделали, но явно всё неправильно. Приводите код, а не "я сделал, оно не работает, способ плохо, код не покажу, я идеален" :D
3) Опять таки нет полного кода :D Ничего сказать не могу.
1 - нет, не так
Это в приложении
Код
C++ (Qt)
   ReadData *thread;
   TCPClientQt s_Client;
.....
   thread=new ReadData(this);
   QObject::connect(&s_Client,SIGNAL(sig_Connected()),this, SLOT(slotIsConnected()),Qt::AutoConnection);
   QObject::connect(&s_Client,SIGNAL(sig_newInfo()),this, SLOT(getNewInfo()),Qt::AutoConnection);
   QObject::connect(&s_Client,SIGNAL(sig_Disconnected()),this, SLOT(slotIsDisonnected()),Qt::AutoConnection);
   s_Client.moveToThread(thread);
 
В конструкторе наследника сокета :
Код
C++ (Qt)
//work
connect(m_pTcpSocket, SIGNAL(connected()), SLOT(slotConnected()));
connect(m_pTcpSocket, SIGNAL(disconnected()), SLOT(slotDisconnected()));
connect(m_pTcpSocket, SIGNAL(readyRead()), SLOT(slotReadyRead()));
//not work
connect(m_pTcpSocket, SIGNAL(error(QAbstractSocket::SocketError)),this, SLOT(slotError(QAbstractSocket::SocketError)));
connect(m_pTcpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState socketState )),this, SLOT(slotStateChanged(QAbstractSocket::SocketState)));
 
2) Хм, классы вывалить?
Портянка получится, но попробую %)
Код
C++ (Qt)
class ReadData : public QThread
{
   Q_OBJECT
 
private:
   int m_Result;
 
public:
   explicit ReadData(QObject *parent = 0);
   ~ReadData();
 
   void run();
 
signals:
 
public slots:
 
};
 
Код
C++ (Qt)
ReadData::ReadData(QObject *parent) :
   QThread(parent)
{
//moveToThread(this);
//&#1087;&#1088;&#1086;&#1073;&#1086;&#1074;&#1072;&#1083; &#1090;&#1091;&#1090;, &#1085;&#1086; &#1087;&#1086;&#1090;&#1086;&#1082; &#1089;&#1072;&#1084; &#1074; &#1089;&#1077;&#1073;&#1103; &#1083;&#1077;&#1079;&#1090;&#1100; &#1085;&#1077; &#1093;&#1086;&#1095;&#1077;&#1090; :)
m_Result=-1;
}
 
void ReadData::run()
{
   try
   {
     exec();
   }catch(const std::exception& ex)
   {
       m_Result=-2;
   }
}
 
ReadData::~ReadData()
{
 
}
 

 //Цикл нужен потому, что с сервера не все данные могут прийти одновременно.
 //Поэтому клиент должен быть в состоянии получать как весь блок целиком,
 //так и только часть блока или даже все блоки сразу.
//размер блока заранее не известен может и 2 к быть, а может и 20 к.
//промышленный контроллер после получения команды старт гонит цепочку байт (8 бит на датчик)
//предваряя посылку признаком начала, а при корректном завершении признак завершения передачи

Код
C++ (Qt)
class TCPClientQt : public QTcpSocket{
Q_OBJECT
 
public:
explicit TCPClientQt();
   ~TCPClientQt();
bool slotStartData(QString _cmdStart);
bool m_IsConnected;
int m_IsThread;//&#1077;&#1089;&#1083;&#1080; &#1074; &#1086;&#1090;&#1076;&#1077;&#1083;&#1100;&#1085;&#1086;&#1084; &#1087;&#1086;&#1090;&#1086;&#1082;&#1077;, &#1090;&#1086; &#1074;&#1099;&#1089;&#1090;&#1072;&#1074;&#1083;&#1103;&#1077;&#1084; 1
int m_RecivedBytes;//&#1089;&#1082;&#1086;&#1083;&#1100;&#1082;&#1086; &#1073;&#1072;&#1081;&#1090; &#1079;&#1072;&#1073;&#1088;&#1072;&#1083;&#1080; &#1080;&#1079; &#1073;&#1091;&#1092;&#1077;&#1088;&#1072;
QString m_StrInfo;
QString m_CmdCfg;
QString m_AnswerCfg;
QString m_CmdStart;
QString m_AnswerStart;
QString m_CmdStop;
QString m_AnswerStop;
QString m_CmdGetTimer;
QString m_CmdResetTimer;
QString m_CmdResetADC;
QTcpSocket *m_pTcpSocket;
QFile m_LogFile;
QString m_ApplPath;
QByteArray arrReadBlock;
//function
QByteArray getCurrentData();
private:
 
//&#1072;&#1076;&#1088;&#1077;&#1089; &#1080; &#1087;&#1086;&#1088;&#1090;
QString m_strHost;
int m_nPort;
//&#1101;&#1090;&#1086; &#1082;&#1086;&#1084;&#1072;&#1085;&#1076;&#1072;
bool isCmd;
//&#1079;&#1072;&#1074;&#1077;&#1088;&#1096;&#1077;&#1085;&#1080;&#1077; &#1076;&#1072;&#1085;&#1085;&#1099;&#1093;
bool isEnd;
//&#1089;&#1082;&#1086;&#1083;&#1100;&#1082;&#1086; &#1086;&#1078;&#1080;&#1076;&#1072;&#1077;&#1084;
uint ExpectedBytes;
//&#1089;&#1082;&#1086;&#1083;&#1100;&#1082;&#1086; &#1087;&#1086;&#1083;&#1091;&#1095;&#1080;&#1083;&#1080;
uint totalBytesRecived;
//&#1089;&#1082;&#1086;&#1083;&#1100;&#1082;&#1086; &#1079;&#1072;&#1073;&#1088;&#1072;&#1083;&#1080; &#1080;&#1079; &#1084;&#1072;&#1089;&#1089;&#1080;&#1074;&#1072;
uint currentPos;
 //QByteArray m_bufferRead;
 
signals:
 void sig_newInfo();
 void sig_Connected();
 void sig_Disconnected();
 
//private slots:
public slots:
void slotReadyRead();
void slotError (QAbstractSocket::SocketError);
void slotSendToServer(QString _cmdSend);
void slotConnected();
void slotDisconnected();
void slotStateChanged ( QAbstractSocket::SocketState socketState );
void slotConnectToServer(QString _ipHost);
void slotClearLog();
void slotCloseConnect();
 
};
 
Код
C++ (Qt)
TCPClientQt::TCPClientQt(): QTcpSocket()
//
{
m_strHost="192.168.1.7";//strHost;
m_nPort=32000;//nPort;
m_CmdCfg="+WIND:80:";//&#1082;&#1086;&#1085;&#1092;&#1080;&#1075;&#1091;&#1088;&#1072;&#1094;&#1080;&#1103; &#1087;&#1088;&#1077;&#1092;&#1080;&#1082;&#1089; &#1082;&#1086;&#1084;&#1072;&#1085;&#1076;&#1099;
m_AnswerCfg="+WIND:81:";//&#1082;&#1086;&#1085;&#1092;&#1080;&#1075;&#1091;&#1088;&#1072;&#1094;&#1080;&#1103; &#1087;&#1088;&#1077;&#1092;&#1080;&#1082;&#1089; &#1086;&#1090;&#1074;&#1077;&#1090;
m_CmdStart="+WIND:82:";//&#1089;&#1090;&#1072;&#1088;&#1090; &#1082;&#1086;&#1084;&#1072;&#1085;&#1076;&#1072;
m_AnswerStart="+WIND:83:";//&#1089;&#1090;&#1072;&#1088;&#1090; &#1087;&#1088;&#1077;&#1092;&#1080;&#1082;&#1089; &#1086;&#1090;&#1074;&#1077;&#1090;
m_CmdStop="+WIND:84:";//&#1089;&#1090;&#1086;&#1087; &#1082;&#1086;&#1084;&#1072;&#1085;&#1076;&#1072;
m_AnswerStop="+WIND:85:";//&#1089;&#1090;&#1086;&#1087; &#1087;&#1088;&#1077;&#1092;&#1080;&#1082;&#1089; &#1086;&#1090;&#1074;&#1077;&#1090;
m_CmdGetTimer="+WIND:89:";//&#1079;&#1072;&#1087;&#1088;&#1086;&#1089; &#1090;&#1072;&#1081;&#1084;&#1077;&#1088;&#1072;
m_CmdResetTimer="+WIND:88:";//&#1089;&#1073;&#1088;&#1086;&#1089; &#1090;&#1072;&#1081;&#1084;&#1077;&#1088;&#1072;
m_CmdResetADC="+WIND:99:";//&#1089;&#1073;&#1088;&#1086;&#1089; &#1040;&#1062;&#1055;
m_pTcpSocket = new QTcpSocket(this);
m_ApplPath=QCoreApplication::applicationDirPath();
m_LogFile.setFileName(m_ApplPath+"/TCPClientQt.log");
m_StrInfo="Empty";
m_IsThread=0;
m_RecivedBytes=0;
m_IsConnected=false;
//&#1087;&#1088;&#1080;&#1079;&#1085;&#1072;&#1082; &#1085;&#1072;&#1083;&#1080;&#1095;&#1080;&#1103; &#1082;&#1086;&#1084;&#1072;&#1085;&#1076;&#1099;
isCmd=false;
isEnd=false;
ExpectedBytes=0;
totalBytesRecived=0;
currentPos=0;
arrReadBlock.clear();
connect(m_pTcpSocket, SIGNAL(connected()), SLOT(slotConnected()));
connect(m_pTcpSocket, SIGNAL(disconnected()), SLOT(slotDisconnected()));
connect(m_pTcpSocket, SIGNAL(readyRead()), SLOT(slotReadyRead()));
connect(m_pTcpSocket, SIGNAL(error(QAbstractSocket::SocketError)),this, SLOT(slotError(QAbstractSocket::SocketError)));
connect(m_pTcpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState socketState )),this, SLOT(slotStateChanged(QAbstractSocket::SocketState)));
}
 
void TCPClientQt::slotClearLog()
{
   //m_ptxtInfo->clear();
}
 
void TCPClientQt::slotCloseConnect()
{
 
   if(m_pTcpSocket->state() == QAbstractSocket::UnconnectedState)
   {
       m_StrInfo="&#1053;&#1077;&#1090; &#1086;&#1090;&#1082;&#1088;&#1099;&#1090;&#1086;&#1075;&#1086; &#1089;&#1086;&#1082;&#1077;&#1090;&#1072;";
   }else{
       m_pTcpSocket->close();
       m_IsConnected=false;
       m_StrInfo="&#1057;&#1086;&#1082;&#1077;&#1090; &#1079;&#1072;&#1082;&#1088;&#1099;&#1090;";
   }
   if(m_LogFile.isOpen())
   {
    QByteArray arr=m_StrInfo.toAscii()+"\n";
     m_LogFile.write(arr);
     m_LogFile.close();
   }
   emit sig_Disconnected();
   emit sig_newInfo();
}
 
void TCPClientQt::slotSendToServer(QString _cmdSend)
{
   if(m_pTcpSocket->state() == QAbstractSocket::ConnectedState)
   {
      m_StrInfo=QTime::currentTime().toString("hh:mm:ss.zzz")+" &#1054;&#1090;&#1087;&#1088;&#1072;&#1074;&#1082;&#1072; &#1082;&#1086;&#1084;&#1072;&#1085;&#1076;&#1099; "+_cmdSend;
      emit sig_newInfo();
      if(m_LogFile.isOpen())
      {
       QByteArray arr=m_StrInfo.toAscii()+"\n";
        m_LogFile.write(arr);
      }
      currentPos=0;
   }else
   {
     m_StrInfo=QTime::currentTime().toString("hh:mm:ss.zzz")+" &#1053;&#1077;&#1090; &#1086;&#1090;&#1082;&#1088;&#1099;&#1090;&#1086;&#1075;&#1086; &#1089;&#1086;&#1077;&#1076;&#1080;&#1085;&#1077;&#1085;&#1080;&#1103;!";
     emit sig_newInfo();
     return;
   }
QByteArray arrSend;
QString cmdSend=_cmdSend;
arrSend=cmdSend.toAscii();
m_pTcpSocket->write(arrSend);
 if(m_LogFile.isOpen())
 {
  QByteArray arr=m_StrInfo.toAscii()+"\n";
   m_LogFile.write(arr);
 }
}
 
 
void TCPClientQt::slotReadyRead()
{
//&#1076;&#1086;&#1089;&#1090;&#1091;&#1087;&#1085;&#1086; &#1073;&#1072;&#1081;&#1090; &#1074; &#1090;&#1077;&#1082;&#1091;&#1097;&#1080;&#1081; &#1084;&#1086;&#1084;&#1077;&#1085;&#1090;
uint bytesAvailable=0;
//&#1087;&#1086;&#1083;&#1091;&#1095;&#1077;&#1085;&#1085;&#1099;&#1077; &#1090;&#1077;&#1082;&#1091;&#1097;&#1080;&#1077; &#1073;&#1072;&#1081;&#1090;&#1099;
QByteArray currArr;
//&#1076;&#1083;&#1103; &#1087;&#1077;&#1088;&#1077;&#1075;&#1086;&#1085;&#1072; &#1074; &#1089;&#1090;&#1088;&#1086;&#1082;&#1091;, &#1077;&#1089;&#1083;&#1080; &#1082;&#1086;&#1084;&#1072;&#1085;&#1076;&#1072; &#1080;&#1083;&#1080; &#1086;&#1090;&#1074;&#1077;&#1090;
QByteArray strArr;
//&#1087;&#1086;&#1083;&#1091;&#1095;&#1077;&#1085;&#1085;&#1072;&#1103; &#1089;&#1090;&#1088;&#1086;&#1082;&#1072; &#1086;&#1090;&#1074;&#1077;&#1090;&#1072; &#1087;&#1086; &#1082;&#1086;&#1084;&#1072;&#1085;&#1076;&#1077; &#1089;&#1090;&#1072;&#1088;&#1090;
QByteArray strAnswerStart;
//&#1088;&#1072;&#1079;&#1084;&#1077;&#1088; &#1086;&#1090;&#1074;&#1077;&#1090;&#1072; &#1074; &#1073;&#1072;&#1081;&#1090;&#1072;&#1093;
//&#1103;&#1103;
int pos=-1;
//&#1088;&#1072;&#1079;&#1084;&#1077;&#1088; &#1082;&#1086;&#1084;&#1072;&#1085;&#1076;&#1099; &#1089; &#1086;&#1090;&#1074;&#1077;&#1090;&#1086;&#1084;
uint sizeCmd=20;
//int bytesArray=0;
//&#1062;&#1080;&#1082;&#1083; &#1085;&#1091;&#1078;&#1077;&#1085; &#1087;&#1086;&#1090;&#1086;&#1084;&#1091;, &#1095;&#1090;&#1086; &#1089; &#1089;&#1077;&#1088;&#1074;&#1077;&#1088;&#1072; &#1085;&#1077; &#1074;&#1089;&#1077; &#1076;&#1072;&#1085;&#1085;&#1099;&#1077; &#1084;&#1086;&#1075;&#1091;&#1090; &#1087;&#1088;&#1080;&#1081;&#1090;&#1080; &#1086;&#1076;&#1085;&#1086;&#1074;&#1088;&#1077;&#1084;&#1077;&#1085;&#1085;&#1086;.
//&#1055;&#1086;&#1101;&#1090;&#1086;&#1084;&#1091; &#1082;&#1083;&#1080;&#1077;&#1085;&#1090; &#1076;&#1086;&#1083;&#1078;&#1077;&#1085; &#1073;&#1099;&#1090;&#1100; &#1074; &#1089;&#1086;&#1089;&#1090;&#1086;&#1103;&#1085;&#1080;&#1080; &#1087;&#1086;&#1083;&#1091;&#1095;&#1072;&#1090;&#1100; &#1082;&#1072;&#1082; &#1074;&#1077;&#1089;&#1100; &#1073;&#1083;&#1086;&#1082; &#1094;&#1077;&#1083;&#1080;&#1082;&#1086;&#1084;,
//&#1090;&#1072;&#1082; &#1080; &#1090;&#1086;&#1083;&#1100;&#1082;&#1086; &#1095;&#1072;&#1089;&#1090;&#1100; &#1073;&#1083;&#1086;&#1082;&#1072; &#1080;&#1083;&#1080; &#1076;&#1072;&#1078;&#1077; &#1074;&#1089;&#1077; &#1073;&#1083;&#1086;&#1082;&#1080; &#1089;&#1088;&#1072;&#1079;&#1091;.
m_RecivedBytes=0;
isEnd=false;
isCmd=false;
if(m_pTcpSocket->state() == QAbstractSocket::UnconnectedState)
{
 
    m_StrInfo=QTime::currentTime().toString("hh:mm:ss.zzz")+" UnconnectedState";
    if(m_LogFile.isOpen())
    {
     QByteArray arr=m_StrInfo.toAscii()+"\n";
      m_LogFile.write(arr);
    }
    emit sig_newInfo();
   return;
}
 while(true){
 
   strArr.clear();
   currArr.clear();
       bytesAvailable=m_pTcpSocket->bytesAvailable();
       if(bytesAvailable < sizeof(quint16)){
           //&#1085;&#1077;&#1090; &#1076;&#1072;&#1085;&#1085;&#1099;&#1093;
           m_StrInfo=QTime::currentTime().toString("hh:mm:ss.zzz")+" bytesAvailable 0 &#1055;&#1091;&#1089;&#1090;&#1086;";
           if(m_LogFile.isOpen())
           {
            QByteArray arr=m_StrInfo.toAscii()+"\n";
             m_LogFile.write(arr);
           }
           emit sig_newInfo();
           break;
       }else
       {
        //
       }
       //&#1077;&#1089;&#1090;&#1100; &#1076;&#1072;&#1085;&#1085;&#1099;&#1077;
       totalBytesRecived=totalBytesRecived+bytesAvailable;
           currArr=m_pTcpSocket->read(bytesAvailable);
           arrReadBlock.append(currArr);
           //&#1077;&#1089;&#1083;&#1080; &#1082;&#1091;&#1089;&#1086;&#1095;&#1077;&#1082; &#1084;&#1077;&#1085;&#1077;&#1077; 20 &#1073;&#1072;&#1081;&#1090;
           if(bytesAvailable<sizeCmd && !currArr.contains(m_AnswerStop.toAscii())){
               strArr=currArr.left(sizeCmd);
               //&#1086;&#1090;&#1074;&#1077;&#1090; &#1082;&#1086;&#1085;&#1092;&#1080;&#1075;&#1091;&#1088;&#1072;&#1094;&#1080;&#1080;
               if(currArr.contains(m_AnswerCfg.toAscii()))
               {
                 strArr=currArr.left(17);
                 m_StrInfo=QTime::currentTime().toString("hh:mm:ss.zzz")+" Answer CFG "
                                    +QString::fromAscii(strArr);
                 if(m_LogFile.isOpen())
                 {
                  QByteArray arr=m_StrInfo.toAscii()+"\n";
                   m_LogFile.write(arr);
                 }
                 emit sig_newInfo();
               }else
               {
                 //
               }
               if(currArr.contains(m_CmdGetTimer.toAscii()))
               {
                   strArr=currArr.left(20);
                   m_StrInfo=QTime::currentTime().toString("hh:mm:ss.zzz")+" Answer GetTimer "
                                      +QString::fromAscii(strArr);
                   if(m_LogFile.isOpen())
                   {
                    QByteArray arr=m_StrInfo.toAscii()+"\n";
                     m_LogFile.write(arr);
                   }
                   emit sig_newInfo();                  
               }else
               {
                 //
               }
               if(currArr.contains(m_CmdResetTimer.toAscii()))
               {
                   strArr=currArr.left(20);
                   m_StrInfo=QTime::currentTime().toString("hh:mm:ss.zzz")+" Answer ResetTimer "
                                      +QString::fromAscii(strArr);
                   if(m_LogFile.isOpen())
                   {
                    QByteArray arr=m_StrInfo.toAscii()+"\n";
                     m_LogFile.write(arr);
                   }
                   emit sig_newInfo();
               }else
               {
                 //
               }
               isCmd=true;
               break;
           }else{
               m_StrInfo=QTime::currentTime().toString("hh:mm:ss.zzz")
                               +" bytesAvailable "+QString::number(bytesAvailable);
               if(m_LogFile.isOpen())
               {
                QByteArray arr=m_StrInfo.toAscii()+"\n";
                 m_LogFile.write(arr);
               }
               emit sig_newInfo();
           }
           //&#1077;&#1089;&#1090;&#1100; &#1085;&#1072;&#1095;&#1072;&#1083;&#1086; +WIND:83:
           if(currArr.contains(m_AnswerStart.toAscii()))
           {
               isCmd=false;
               pos=17;
               strArr=currArr.left(pos);
               m_StrInfo=QTime::currentTime().toString("hh:mm:ss.zzz")
                                  +" Begin "+QString::fromAscii(strArr);
               if(m_LogFile.isOpen())
               {
                QByteArray arr=m_StrInfo.toAscii()+"\n";
                 m_LogFile.write(arr);
               }
               //&#1074;&#1099;&#1103;&#1089;&#1085;&#1103;&#1077;&#1084;, &#1089;&#1082;&#1086;&#1083;&#1100;&#1082;&#1086; &#1073;&#1072;&#1081;&#1090; &#1076;&#1086;&#1083;&#1078;&#1085;&#1086; &#1087;&#1088;&#1080;&#1083;&#1077;&#1090;&#1077;&#1090;&#1100; &#1080;&#1089;&#1093;&#1086;&#1076;&#1103; &#1080;&#1079; &#1079;&#1072;&#1075;&#1086;&#1083;&#1086;&#1074;&#1082;&#1072; &#1086;&#1090;&#1074;&#1077;&#1090;&#1072; &#1089;&#1077;&#1088;&#1074;&#1077;&#1088;&#1072; +WIND:83:XX:XX:XX
               //&#1088;&#1072;&#1079;&#1073;&#1086;&#1088; &#1079;&#1072;&#1075;&#1086;&#1083;&#1086;&#1074;&#1082;&#1072;
               strAnswerStart.clear();
               strAnswerStart.append(strArr.data()[9]);
               strAnswerStart.append(strArr.data()[10]);
               int F=strAnswerStart.toInt();
               strAnswerStart.clear();
               strAnswerStart.append(strArr.data()[12]);
               strAnswerStart.append(strArr.data()[13]);
               int C=strAnswerStart.toInt();
               strAnswerStart.clear();
               strAnswerStart.append(strArr.data()[15]);
               strAnswerStart.append(strArr.data()[16]);
               int T=strAnswerStart.toInt();
               strAnswerStart.clear();
               //&#1089;&#1082;&#1086;&#1083;&#1100;&#1082;&#1086; &#1073;&#1072;&#1081;&#1090;
               ExpectedBytes=F*1000*C*T+34;
               emit sig_newInfo();
           }else{
               //
           }
           //&#1077;&#1089;&#1090;&#1100; &#1082;&#1086;&#1085;&#1077;&#1094;
           if(currArr.contains(m_AnswerStop.toAscii()))
           {
               isEnd=true;
               pos=arrReadBlock.indexOf(m_AnswerStop);
               strArr=currArr.right(17);
               m_StrInfo=QTime::currentTime().toString("hh:mm:ss.zzz")
                                  +" End "+QString::fromAscii(strArr);
               if(m_LogFile.isOpen())
               {
                QByteArray arr=m_StrInfo.toAscii()+"\n";
                 m_LogFile.write(arr);
               }
               emit sig_newInfo();
               break;
 
           }else{
             //
           }
 
       //&#1080; &#1085;&#1072; &#1085;&#1086;&#1074;&#1099;&#1081; &#1094;&#1080;&#1082;&#1083; &#1087;&#1086;&#1089;&#1083;&#1077; &#1086;&#1078;&#1080;&#1076;&#1072;&#1085;&#1080;&#1103;
       m_pTcpSocket->waitForReadyRead(550);//&#1074;&#1088;&#1077;&#1084;&#1103; &#1086;&#1078;&#1080;&#1076;&#1072;&#1085;&#1080;&#1103; &#1086;&#1095;&#1077;&#1088;&#1077;&#1076;&#1085;&#1086;&#1075;&#1086; &#1087;&#1072;&#1082;&#1077;&#1090;&#1072; &#1074;  &#1084;&#1089;
}
 //&#1079;&#1072;&#1074;&#1077;&#1088;&#1096;&#1077;&#1085;&#1080;&#1077; &#1087;&#1088;&#1080;&#1077;&#1084;&#1072; &#1076;&#1072;&#1085;&#1085;&#1099;&#1093;
 if(isEnd)
 {
   m_StrInfo=QTime::currentTime().toString("hh:mm:ss.zzz")
                     +" Total Expected: "
                     +QString::number(ExpectedBytes);
   if(m_LogFile.isOpen())
   {
    QByteArray arr=m_StrInfo.toAscii()+"\n";
     m_LogFile.write(arr);
   }
   emit sig_newInfo();
    m_StrInfo=QTime::currentTime().toString("hh:mm:ss.zzz")
                    +" Total Recive: "
                    +QString::number(totalBytesRecived);
    if(m_LogFile.isOpen())
    {
     QByteArray arr=m_StrInfo.toAscii()+"\n";
      m_LogFile.write(arr);
    }
   emit sig_newInfo();
   m_StrInfo=QTime::currentTime().toString("hh:mm:ss.zzz")
                    +" Lost: "
                    +QString::number(ExpectedBytes-totalBytesRecived);
   if(m_LogFile.isOpen())
   {
    QByteArray arr=m_StrInfo.toAscii()+"\n";
     m_LogFile.write(arr);
   }
   emit sig_newInfo();
   isEnd=false;
 }
totalBytesRecived=0;
ExpectedBytes=0;
arrReadBlock.clear();
return;
}
 
 
 
void TCPClientQt::slotError(QAbstractSocket::SocketError err)
{
QString strError =
   (err == QAbstractSocket::HostNotFoundError ?
   "The host was not found. "+QString::number(-1) :
   err == QAbstractSocket::RemoteHostClosedError ?
   "The remote host is closed. "+QString::number(-2) :
   err == QAbstractSocket::ConnectionRefusedError ?
   "The connection was refused. "+QString::number(-3) :
   QString(m_pTcpSocket->errorString())
);
 
   m_StrInfo=QTime::currentTime().toString("hh:mm:ss.zzz")+" Error: "+strError;
   if(m_LogFile.isOpen())
   {
   QByteArray arr=m_StrInfo.toAscii()+"\n";
   m_LogFile.write(arr);
   }
emit sig_newInfo();
}
 
void TCPClientQt::slotStateChanged(QAbstractSocket::SocketState socketState)
{
    m_StrInfo=QTime::currentTime().toString("hh:mm:ss.zzz")+" StateChanged";
   if(m_LogFile.isOpen())
   {
     QByteArray arr=m_StrInfo.toAscii()+"\n";
     m_LogFile.write(arr);
   }
}
 
void TCPClientQt::slotConnected()
{
 
   m_StrInfo=QTime::currentTime().toString("hh:mm:ss.zzz")+" Connected";
   m_IsConnected=true;
   emit sig_Connected();
   emit sig_newInfo();
   if(!m_LogFile.isOpen())
   {
       m_LogFile.open(QIODevice::ReadWrite);
       m_LogFile.seek(m_LogFile.size());
       QByteArray arr=m_StrInfo.toAscii()+"\n";
       m_LogFile.write(arr);
   }
}
 
void TCPClientQt::slotDisconnected()
{
   m_StrInfo=m_StrInfo=QTime::currentTime().toString("hh:mm:ss.zzz")+" Disconnected";
   if(m_LogFile.isOpen())
   {
    QByteArray arr=m_StrInfo.toAscii()+"\n";
     m_LogFile.write(arr);
     m_LogFile.close();
   }
   m_IsConnected=false;
   emit sig_Disconnected();
}
 
QByteArray TCPClientQt::getCurrentData()
{
   QByteArray result;
   .....
   return result;
}
 
void TCPClientQt::slotConnectToServer(QString _ipHost)
{
   if(m_pTcpSocket!=0)
   {
   if(m_pTcpSocket->state() == QAbstractSocket::UnconnectedState)
   {
       m_strHost=_ipHost;
       m_pTcpSocket->connectToHost(m_strHost, m_nPort);
   }else{
       m_StrInfo=QTime::currentTime().toString("hh:mm:ss.zzz")+" &#1045;&#1089;&#1090;&#1100; &#1086;&#1090;&#1082;&#1088;&#1099;&#1090;&#1086;&#1077; &#1089;&#1086;&#1077;&#1076;&#1080;&#1085;&#1077;&#1085;&#1080;&#1077;";
       emit sig_newInfo();
   }
   }else
   {
       //
   }
   if(m_LogFile.isOpen())
   {
       QByteArray arr=m_StrInfo.toAscii()+"\n";
       m_LogFile.write(arr);
   }
}
 
TCPClientQt::~ TCPClientQt ()
{
   if(m_LogFile.isOpen())
   {
     m_LogFile.close();
   }
   if(m_pTcpSocket!=0)
   { if(m_pTcpSocket->state() != QAbstractSocket::UnconnectedState)
       {
        m_pTcpSocket->close();
       }else
       {
           //
       }
       m_pTcpSocket=0;
   }
}
 

Блин, все комменты на русском злобно перегнало в другую кодировку
Как побороть не знаю. :(

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

Код
C++ (Qt)
ReadData::ReadData(QObject *parent) :
   QThread(parent)
{
 
m_Client=new TCPClientQt(this);
QObject::connect(m_Client,SIGNAL(sig_Connected()),this->parent(), SLOT(slotIsConnected()),Qt::AutoConnection);
QObject::connect(m_Client,SIGNAL(sig_newInfo()),this->parent(), SLOT(getNewInfo()),Qt::AutoConnection);
QObject::connect(m_Client,SIGNAL(sig_Disconnected()),this->parent(), SLOT(slotIsDisonnected()),Qt::AutoConnection);
moveToThread(this);
}
//&#1090;&#1077;&#1089;&#1090; &#1082;&#1086;&#1076;&#1080;&#1088;&#1086;&#1074;&#1082;&#1080;
 


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: stix357 от Декабрь 21, 2016, 11:18
Далее:
то что
не отрабатывает
Код
C++ (Qt)
void TCPClientQt::slotError(QAbstractSocket::SocketError err)
 
наврал
отрабатывает при попытке получения пакета в
Код
C++ (Qt)
void
connect(m_pTcpSocket, SIGNAL(readyRead()), SLOT(slotReadyRead()));
 
только по Network operation timed out
На остальные ошибки  ... типо плевать
Хоть IP задавай несуществующий, хоть порт левый ....
тупо отправляется SYNC и полный завис (смотрю в Tcpview)
ClientADC_QT.exe   1844   TCP   pc-win7060.dlink   50120   192.168.1.200   32000   SYN_SENT                              
и в Wireshark чисто, чисто, чисто
А при запуске из основного потока с ГУИ все робит ...... парадокс


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: stix357 от Декабрь 29, 2016, 09:05
Цитата: Bepec
2) создать наследника от QThread и в нём в конструкторе сделать moveToThread(this). И в этом наследнике творите что хотите.
Вообще довольно спорный способ переносить объект QThread в самого себя в конструкторе.
До отработки конструктора объект еще не существует.


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: Bepec от Декабрь 29, 2016, 13:18
Неверно.
Сначала создаётся объект.
Потом вызывается конструктор.
Всё есть.


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: stix357 от Декабрь 30, 2016, 11:55
Неверно.
Сначала создаётся объект.
Потом вызывается конструктор.
Всё есть.
Только заготовка. Благодаря опять-таки конструктору предка.
2) создать наследника от QThread и в нём в конструкторе сделать moveToThread(this). И в этом наследнике творите что хотите.
Не сочтите за наглость, но возможно вас не затруднит показать простенький работающий пример по вашему методу?
QTcpSocket в отдельном QThread
Если я правильно понял, то должно выглядеть примерно так:
Код
C++ (Qt)
ReadData::ReadData(QObject *parent) :
   QThread(parent)
{
m_Socket=new QTcpSocket(this);
moveToThread(this);
}
 


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: Bepec от Декабрь 30, 2016, 15:48
Вы не понимаете...
Вы сначала создаёте объект... потом перемещаете все слоты потока в самого себя :D Объект при этом у вас никуда не перемещается.

Примерчик. Самый примитив.
https://dl.dropboxusercontent.com/u/62712483/Temp.zip


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: stix357 от Январь 09, 2017, 14:47
Вы не понимаете...
Вы сначала создаёте объект... потом перемещаете все слоты потока в самого себя :D Объект при этом у вас никуда не перемещается.

Примерчик. Самый примитив.
https://dl.dropboxusercontent.com/u/62712483/Temp.zip
Благодарю, буду сравнивать и смотреть где напортачил. Руки пока не доходили.


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: stix357 от Январь 11, 2017, 07:23
Примерчик. Самый примитив.
https://dl.dropboxusercontent.com/u/62712483/Temp.zip
Вопрос возник:
если по вашему примеру
Код
C++ (Qt)
void SBThread::run()
{
   m_pTcpSocket = new QTcpSocket(this);
 
   connect(m_pTcpSocket, SIGNAL(connected()), SLOT(slotConnected()));
   connect(m_pTcpSocket, SIGNAL(disconnected()), SLOT(disconnected()));
   connect(m_pTcpSocket, SIGNAL(readyRead()), SLOT(readyRead()));
   connect(m_pTcpSocket, SIGNAL(error(QAbstractSocket::SocketError)),this, SLOT(error(QAbstractSocket::SocketError)));
....
 
то что произойдет с распределением памяти при завершении void SBThread::run()?
выделенная память под m_pTcpSocket сама освободится или это надо делать ручками?


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: Пантер от Январь 11, 2017, 08:58
Объект сокета будет жить, пока жив класс потока. Создавай на стеке.


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: stix357 от Январь 11, 2017, 09:21
Объект сокета будет жить, пока жив класс потока. Создавай на стеке.

Mмм, не понял фразу Создавай на стеке.

А если так?
Код
C++ (Qt)
void SBThread::run()
{
   QTcpSocket m_pTcpSocket;
 
   connect(&m_pTcpSocket, SIGNAL(connected()), SLOT(slotConnected()));
   connect(&m_pTcpSocket, SIGNAL(disconnected()), SLOT(disconnected()));
   connect(&m_pTcpSocket, SIGNAL(readyRead()), SLOT(readyRead()));
   connect(&m_pTcpSocket, SIGNAL(error(QAbstractSocket::SocketError)),this, SLOT(error(QAbstractSocket::SocketError)));
....
 


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: Пантер от Январь 11, 2017, 09:24
Так объект сокета разрушится при выходе из метода run. Это и есть на стеке.


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: Пантер от Январь 11, 2017, 09:25
Еще советую не наследоваться от QThread, а делать moveToThread. На форуме есть обсуждение данного совета со ссылками.


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: gil9red от Январь 11, 2017, 09:35
Еще советую не наследоваться от QThread, а делать moveToThread. На форуме есть обсуждение данного совета со ссылками.

В доке написано что можно и так, и так :)
http://doc.qt.io/qt-5/qthread.html#details

// You can use worker objects by moving them to the thread using QObject::moveToThread().
Код
C++ (Qt)
class Worker : public QObject
{
   Q_OBJECT
 
public slots:
   void doWork(const QString &parameter) {
       QString result;
       /* ... here is the expensive or blocking operation ... */
       emit resultReady(result);
   }
 
signals:
   void resultReady(const QString &result);
};
 
class Controller : public QObject
{
   Q_OBJECT
   QThread workerThread;
public:
   Controller() {
       Worker *worker = new Worker;
       worker->moveToThread(&workerThread);
       connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
       connect(this, &Controller::operate, worker, &Worker::doWork);
       connect(worker, &Worker::resultReady, this, &Controller::handleResults);
       workerThread.start();
   }
   ~Controller() {
       workerThread.quit();
       workerThread.wait();
   }
public slots:
   void handleResults(const QString &);
signals:
   void operate(const QString &);
};
 

// Another way to make code run in a separate thread, is to subclass QThread and reimplement run(). For example:
Код
C++ (Qt)
class WorkerThread : public QThread
{
   Q_OBJECT
   void run() Q_DECL_OVERRIDE {
       QString result;
       /* ... here is the expensive or blocking operation ... */
       emit resultReady(result);
   }
signals:
   void resultReady(const QString &s);
};
 
void MyObject::startWorkInAThread()
{
   WorkerThread *workerThread = new WorkerThread(this);
   connect(workerThread, &WorkerThread::resultReady, this, &MyObject::handleResults);
   connect(workerThread, &WorkerThread::finished, workerThread, &QObject::deleteLater);
   workerThread->start();
}
 


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: Пантер от Январь 11, 2017, 09:48
gil9red, ну, ясен пень, что не расстреляют за любой из способов. Просто я считаю, что наследование худший выбор. Вообще, ИМХО, лучше сначала все писать без потоков (на ассинхронке), а потом выносить в потоки нужные части, при этом moveToThread будет лучшим решением, чем изменение наследования.


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: stix357 от Январь 11, 2017, 10:08
Объект сокета будет жить, пока жив класс потока. Создавай на стеке.
Вот я и думаю, как на утечки памяти не напороться ...
Ведь в случае
Код
C++ (Qt)
void SBThread::run()
{
   m_pTcpSocket = new QTcpSocket(this);
 
   connect(m_pTcpSocket, SIGNAL(connected()), SLOT(slotConnected()));
   connect(m_pTcpSocket, SIGNAL(disconnected()), SLOT(disconnected()));
   connect(m_pTcpSocket, SIGNAL(readyRead()), SLOT(readyRead()));
   connect(m_pTcpSocket, SIGNAL(error(QAbstractSocket::SocketError)),this, SLOT(error(QAbstractSocket::SocketError)));
....
 
если я объекту SBThread потока дам команду quit(), то m_pTcpSocket  в памяти останется
но если потом скажу объекту SBThread - start(), то получается дубликат m_pTcpSocket будет создан .... а старый повиснет непонятно где.
Ладно, спасибо, буду экспереминтировать.


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: Пантер от Январь 11, 2017, 10:14
Да, будет утечка. Либо в run проверку делай
Код
C++ (Qt)
if (!m_pTcpSocket) {
 m_pTcpSocket = new QTcpSocket(this);
}
 
Либо создавай на стеке.


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: stix357 от Январь 11, 2017, 10:51
Да, будет утечка. Либо в run проверку делай
Код
C++ (Qt)
if (!m_pTcpSocket) {
 m_pTcpSocket = new QTcpSocket(this);
}
 
Либо создавай на стеке.
А при moveToThread что произойдет с объектом при завершении run() в двух вариантах?
1)
Код
C++ (Qt)
thread=new QThread(this);
socket=new QTcpSocket(this);
socket->moveToThread(thread);
 
2)
Код
C++ (Qt)
thread=new QThread(this);
QTcpSocket socket;
socket->moveToThread(thread);
 
Я просто не в курсе, как в QT утечки отследить, всего месяц с ним работаю.


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: Авварон от Январь 11, 2017, 11:00
+1 за moveToThread. Переопределение run() нужно если дергается одна ф-ия и нет сигнал-слотового взаимодействия.
И указывать this у перемещаемого класса нельзя, перемещать можно только объекты без родителя (точнее, только топ-левел объект иерархии).


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: Пантер от Январь 11, 2017, 11:13
stix357, просто QTcpSocket смысла нет переносить в поток. Да и вообще, тебе тут поток не нужен, если работаешь с сокетом сигналами/слотами. Вот тебе пример с moveToThread.

Код
C++ (Qt)
class Calculator : public QObject
{
Q_OBJECT
signals:
 void finished (int sum);
public slots:
   void calculate () {
       int result = 0;
       for (int i = 0; i < 99999; ++i) {
               result += i;
       }
 
       emit finished (result);
   }
}
 
.............................
Calculator *calculator = new Calculator;
QThread *thread = new QThread
 
calculator->moveToThread (thread);
connect(thread, &QThread::started, calculator, &Calculator::calculate);
connect(thread, &QThread::finished, calculator, &Calculator::deleteLater);
 
connect(calculator, &Calculator::finished, [] (int result) {qDebug () << result;});
connect(calculator, &Calculator::finished, thread, &QThread::quit);
connect(calculator, &Calculator::destroyed, thread, &QThread::deleteLater);
thread->start();
 
 

Что непонятно, спрашивай. Писал в браузере - возможны ошибки.


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: stix357 от Январь 11, 2017, 11:48
stix357, просто QTcpSocket смысла нет переносить в поток. Да и вообще, тебе тут поток не нужен, если работаешь с сокетом сигналами/слотами. Вот тебе пример с moveToThread.
----
Что непонятно, спрашивай. Писал в браузере - возможны ошибки.

Спасибо, пока сижу перевариваю.


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: stix357 от Январь 11, 2017, 12:39
stix357, просто QTcpSocket смысла нет переносить в поток. Да и вообще, тебе тут поток не нужен, если работаешь с сокетом сигналами/слотами.
Тут у меня затык в том, что клиент с QTcpSocket получает данные непрерывно с контроллера, пока не получит код завершения.
Обрабатывать данные надо по мере поступления очередных пакетов.
Поэтому приходится на сигнал сокета
Код
C++ (Qt)
SIGNAL(readyRead())
вешать дурную конструкцию типа
Код
C++ (Qt)
void TCPClientQt::slotReadyRead()
{
....
isEnd=false;
isCmd=false;
 while(true)
 {
    currArr=read(now_BytesAvailable);
       totalBytesRecived=totalBytesRecived+now_BytesAvailable;
           if(now_BytesAvailable < sizeCmd && !currArr.contains(m_AnswerStop.toAscii())){
 
.//..
               isCmd=true;
               break;
           }else{
//....
           }
           arrReadBlock.append(currArr);
//...
                  if(currArr.contains(m_AnswerStop.toAscii())){              
//..
               break;
       waitForReadyRead(900);//
}
 //
 if(isEnd)
 {
    m_StrInfo=QTime::currentTime().toString("hh:mm:ss.zzz")
                    +" R bytes: "
                    +QString::number(totalBytesRecived);
    emit sig_newInfo();
return;
}
 
А пока данные принимаются - если в основном потоке, то он висит.


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: Пантер от Январь 11, 2017, 13:09
waitForReadyRead(900); фтопку, остальное отрабатывает доли секунды.


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: stix357 от Январь 11, 2017, 14:32
waitForReadyRead(900); фтопку
Не, к сожалению низя, тогда не успевает очередной пакет получить и нагло из цикла выходит на проверке в начале цикла
Код
C++ (Qt)
       if(now_BytesAvailable < sizeof(quint16)){
           m_StrInfo=QTime::currentTime().toString("hh:mm:ss.zzz")+" 0 bytes";
           emit sig_newInfo();
           break;
 
waitForReadyRead(500) - это минимально
Сам не могу понять почему, разве что сеть WiFi и максимальная скорость канала 56 кбит у радиомодуля при контроллере.

Вопрос возник: обязательно сигналы со слотами после создания потомка  QTcpSocket связывать во внешней среде, так сказать?
я создал потомка
Код
C++ (Qt)
TCPClientQt::TCPClientQt(QObject *parent): QTcpSocket(parent)
 
и у него в конструкторе прописал:
Код
C++ (Qt)
connect(this, SIGNAL(connected()), SLOT(slotConnected()),Qt::AutoConnection);
connect(this, SIGNAL(disconnected()), SLOT(slotDisconnected()),Qt::AutoConnection);
connect(this, SIGNAL(readyRead()), SLOT(slotReadyRead()),Qt::AutoConnection);
connect(this, SIGNAL(error(QAbstractSocket::SocketError)), this,SLOT(slotError(QAbstractSocket::SocketError)),Qt::AutoConnection);
connect(this, SIGNAL(stateChanged(QAbstractSocket::SocketState)),this, SLOT(slotStateChanged(QAbstractSocket::SocketState)),Qt::AutoConnection);
 

и вот эти в отдельном потоке работают нормально
Код
C++ (Qt)
connect(this, SIGNAL(connected()), SLOT(slotConnected()),Qt::AutoConnection);
connect(this, SIGNAL(disconnected()), SLOT(slotDisconnected()),Qt::AutoConnection);
connect(this, SIGNAL(readyRead()), SLOT(slotReadyRead()),Qt::AutoConnection);
 
а вот эти не желают
Код
C++ (Qt)
connect(this, SIGNAL(error(QAbstractSocket::SocketError)), this,SLOT(slotError(QAbstractSocket::SocketError)),Qt::AutoConnection);
connect(this, SIGNAL(stateChanged(QAbstractSocket::SocketState)),this, SLOT(slotStateChanged(QAbstractSocket::SocketState)),Qt::AutoConnection);
 

А в основном потоке нормально отрабатывают все


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: Пантер от Январь 11, 2017, 14:40
> Не, к сожалению низя, тогда не успевает очередной пакет получить и нагло из цикла выходит на проверке в начале цикла

Так ты и должен выйти из цикла, положив то, что пришло во внутренний буфер. Со следующими данными попробуешь распарсить.

Как пример, ты ждешь строку. Допустим, строка - это последовательность символов, заканчивающаяся переводом строки. На readyRead ты вычитываешь все, что есть из сокета и ищешь перенос строки - если он есть, обрабатываешь строку, если нету, ждешь дальше. На следующий readyRead ты дочитываешь в буфер все, что пришло и опять производишь поиск.


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: stix357 от Январь 11, 2017, 15:01
> Не, к сожалению низя, тогда не успевает очередной пакет получить и нагло из цикла выходит на проверке в начале цикла

Так ты и должен выйти из цикла, положив то, что пришло во внутренний буфер. Со следующими данными попробуешь распарсить.

Как пример, ты ждешь строку. Допустим, строка - это последовательность символов, заканчивающаяся переводом строки. На readyRead ты вычитываешь все, что есть из сокета и ищешь перенос строки - если он есть, обрабатываешь строку, если нету, ждешь дальше. На следующий readyRead ты дочитываешь в буфер все, что пришло и опять производишь поиск.
Не, в моем случае этот фокус не пройдет. Я уже пробовал. Тогда радимодуль начинает дурить и вешается. Летит поток байт, и только в самом конце признак окончания передачи.


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: Пантер от Январь 11, 2017, 15:14
Ты что-то делаешь не так. :)


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: Пантер от Январь 11, 2017, 15:14
Попробуй выводить в консоль в hex то, что тебе приходит и проанализируй вручную.


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: stix357 от Январь 11, 2017, 17:48
Попробуй выводить в консоль в hex то, что тебе приходит и проанализируй вручную.
Это про передачу данных от контроллера?
Да я так знаю, что там летит :)
Сначала заголовок 17 байт в символах , потом цепочка байтов летит от 00 до FF на канал, затем символьный хвост завершения 19 байт.
Просто по связке:
Код
C++ (Qt)
connect(m_pTcpSocket, SIGNAL(readyRead()), SLOT(slotReadyRead()));
slotReadyRead - не вызывается второй раз, если убрать из цикла
waitForReadyRead(700);//время ожидания очередного пакета
Не успевает радиомодуль контроллера кинуть очередной пакет.
А радиомудуль гонит пакетами в 738 и второй  281 байт.
А у меня клиент смотрит, в цикле, что пусто:
bytesAvailable=m_pTcpSocket->bytesAvailable();
И вылетает из цикла. Убегаем на конец slotReadyRead и усе.
Радиомодуль долбится, ко мне, как клиенту. Но SIGNAL(readyRead()) не срабатывает.
У него (радиомодуля) буфер переполняется (2048 байт) и все, он уходит в аут.
Поэтому я заставляю подождать очередной порции - waitForReadyRead(700)


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: Авварон от Январь 11, 2017, 18:01
Радиомодуль долбится, ко мне, как клиенту. Но SIGNAL(readyRead()) не срабатывает.

Какая-то хрень, оно должно попадать в буфер принимающей ОС.


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: stix357 от Январь 11, 2017, 18:07
Радиомодуль долбится, ко мне, как клиенту. Но SIGNAL(readyRead()) не срабатывает.

Какая-то хрень, оно должно попадать в буфер принимающей ОС.
А толку-то? если клиент забил на прием?
Размер изначального пакета неизвестен. Клиент считает, что принял все.
И получаю я RST/ACK


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: Old от Январь 11, 2017, 18:16
А толку-то? если клиент забил на прием?
Размер изначального пакета неизвестен. Клиент считает, что принял все.
И получаю я RST/ACK
Вот вам и говорят, что у вас сделано неправильно.


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: stix357 от Январь 12, 2017, 07:48
А толку-то? если клиент забил на прием?
Размер изначального пакета неизвестен. Клиент считает, что принял все.
И получаю я RST/ACK
Вот вам и говорят, что у вас сделано неправильно.
Возможно и так.
Если есть желание - посмотрите, где я ошибся.
https://drive.google.com/file/d/0Bxq5cvEHXCjyVDA3ZVdyXzR4RGM/view?usp=sharing
Прототип клиента
Если убрать из кода:
Код
C++ (Qt)
m_pTcpSocket->waitForReadyRead(550);//время ожидания очередного пакета в  мс
То все, .... получаю только первый пакет. Скриншот ниже. Клиент (192.168.1.12) говорит - усе я принял, больше не надо.
Цитировать
7   4.767455000   192.168.1.12   192.168.1.200   TCP   54   triquest-lm > 32000 [FIN, ACK] Seq=10 Ack=731 Win=65535 Len=0
и отстань от меня сервер
Цитировать
9   4.769592000   192.168.1.12   192.168.1.200   TCP   54   triquest-lm > 32000 [RST, ACK] Seq=11 Ack=1020 Win=0 Len=0
Цитировать
09:57:00.890 ConnectToServer
09:57:00.906 Connected
Delay connect: 16 ms
09:57:04.468 Send +WIND:82:
09:57:04.640 bytesAvailable 730
09:57:04.640 Begin +WIND:83:01:06:03
09:57:04.640 bytesAvailable 0 Пусто
Delay no Data: 172 ms
09:57:04.640 Total Expected: 18034
09:57:04.640 Total Recive: 730
09:57:04.640 Lost: 17304
При включенном ожидании:
Цитировать
Log out
10:19:58.609 ConnectToServer
10:19:58.625 Connected
Delay connect: 16 ms
10:20:01.703 Send +WIND:82:
10:20:01.953 bytesAvailable 730
10:20:01.953 Begin +WIND:83:01:06:03
10:20:02.125 bytesAvailable 730
10:20:02.125 bytesAvailable 578
10:20:02.296 bytesAvailable 730
10:20:02.468 bytesAvailable 730
10:20:02.468 bytesAvailable 578
10:20:02.640 bytesAvailable 730
10:20:02.812 bytesAvailable 289
10:20:02.812 bytesAvailable 730
10:20:02.812 bytesAvailable 289
10:20:02.968 bytesAvailable 730
10:20:02.968 bytesAvailable 289
10:20:03.140 bytesAvailable 730
10:20:03.312 bytesAvailable 730
10:20:03.312 bytesAvailable 578
10:20:03.484 bytesAvailable 730
10:20:03.687 bytesAvailable 289
10:20:03.687 bytesAvailable 730
10:20:03.687 bytesAvailable 289
10:20:03.828 bytesAvailable 730
10:20:03.828 bytesAvailable 289
10:20:04.000 bytesAvailable 730
10:20:04.000 bytesAvailable 289
10:20:04.156 bytesAvailable 730
10:20:04.328 bytesAvailable 730
10:20:04.328 bytesAvailable 578
10:20:04.500 bytesAvailable 730
10:20:04.671 bytesAvailable 289
10:20:04.671 bytesAvailable 730
10:20:04.671 bytesAvailable 289
10:20:04.890 bytesAvailable 711
10:20:04.890 End +WIND:85:00000000
10:20:04.890 Total Expected: 18034
10:20:04.890 Total Recive: 18034
10:20:04.890 Lost: 0


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: Old от Январь 12, 2017, 10:08
Код
C++ (Qt)
class TCPClient : ...
{
   ...
private:
   QByteArray m_buffer;
};
 
// Слот обработки сигнала readyRead()
void TCPClient::onReadData()
{
   m_buffer += readAll();
 
   // Мы все вычитываем в буфер m_buffer
   // Здесь мы может проверить находится ли в буфере полный пакет данных для обработки, если да - обрабатываем его и выкусываем из буфера
   // Если в буфере осталась только часть пакета, то просто выходим и ждем следующую порцию данных
}
 

Пакет по сети может не прийти полностью или могут прийти сразу несколько пакетов, и все это нужно полноценно разбирать.
Пришла только часть пакета - положили ее в буфер и ушли ждать новую порцию данных.
Пришли несколько пакетов сразу - обработали их все и если остался не полный пакет, то оставили его в буфере и ушли ждать новую порцию данных.

P.S. даже можно прием и разбор пакетов производить в разных местах.


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: stix357 от Январь 12, 2017, 10:12
Пакет по сети может не прийти полностью или могут прийти сразу несколько пакетов, и все это нужно полноценно разбирать.
Пришла только часть пакета - положили ее в буфер и ушли ждать новую порцию данных.
А как в ожидание уйти?
Пришли несколько пакетов сразу - обработали их все и если остался не полный пакет, то оставили его в буфере и ушли ждать новую порцию данных.
P.S. даже можно прием и разбор пакетов производить в разных местах.
Мне изначально неизвестен размер пакета.
Цитировать
Передаваемые данные с сервера АЦП начинаются с признака начала передачи
строка +WIN:83:XX:XX:XX, затем без отрыва идут данные сэмплами по байту в HEX формате на канал (значение по каналу от 00 до FF), завершает передачу строка ответа о подтверждении завершения измерений +WIND:85:ХХХХХХХХ


А readAll(); это что?


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: Old от Январь 12, 2017, 10:44
А как в ожидание уйти?
Просто выйти из слота обработчика.

Мне изначально неизвестен размер пакета.
У вас в m_buffer будут все данные, ищите в нем начальный/конечный маркер, или как там вы длину определяете.

А readAll(); это что?
QByteArray QIODevice::readAll()

Сокет наследник QIODevice.


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: stix357 от Январь 12, 2017, 11:39
А как в ожидание уйти?
Просто выйти из слота обработчика.

Мне изначально неизвестен размер пакета.
У вас в m_buffer будут все данные, ищите в нем начальный/конечный маркер, или как там вы длину определяете.

А readAll(); это что?
QByteArray QIODevice::readAll()

Сокет наследник QIODevice.
Хм, огромное спасибо. Мой дурацкий цикл идет нафиг.
А как мне узнать сколько я получил в порции(пакете), не пересчитывая каждый раз m_buffer ?


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: Пантер от Январь 12, 2017, 11:49
> А как мне узнать сколько я получил в порции(пакете), не пересчитывая каждый раз m_buffer ?
Конкретизируй вопрос.


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: stix357 от Январь 12, 2017, 12:10
> А как мне узнать сколько я получил в порции(пакете), не пересчитывая каждый раз m_buffer ?
Конкретизируй вопрос.
Ммм ... Вот такая штука по совету Old (Да хранят его боги!) получилась
Код
C++ (Qt)
// Слот обработки сигнала readyRead()
void TCPClientQt::onReadData()
{
 
   QString strArr="";
   int pos;
   m_ReadBuffer += m_pTcpSocket->readAll();
   //m_ptxtInfo->append(QTime::currentTime().toString("hh:mm:ss.zzz")
                      //+" onReadData "+QString::number(m_ReadBuffer.size()));
   //m_count=m_pTcpSocket->bytesAvailable()+m_count;m_count=+m_count;
   // Мы все вычитываем в буфер m_buffer
   // Здесь мы можем проверить находится ли в буфере полный пакет данных для обработки, если да - обрабатываем его и выкусываем из буфера
   if(!isBegin && m_ReadBuffer.contains("+WIND:83:"))
   {
       pos=17;
       strArr=m_ReadBuffer.left(pos);
       m_ptxtInfo->append(QTime::currentTime().toString("hh:mm:ss.zzz")
                          +" Begin "+QString::fromAscii("+WIND:83:"));
       isBegin=true;
   }
   if(!isEnd && m_ReadBuffer.contains("+WIND:85:"))
   {
       pos=m_ReadBuffer.indexOf("+WIND:85:");
       strArr=m_ReadBuffer.right(17);
       m_ptxtInfo->append(QTime::currentTime().toString("hh:mm:ss.zzz")
                          +" End "+QString::fromAscii("+WIND:85:"));
      isEnd=true;
   }
   m_ptxtInfo->append(QTime::currentTime().toString("hh:mm:ss.zzz")
                      +" Recive "+QString::number(m_count));
   //Если в буфере осталась только часть пакета, то просто выходим и ждем следующую порцию данных
}
 
Я хочу узнать сколько прибежало в пакете, дабы посчитать сумму не бегая каждый раз по размеру m_ReadBuffer.size() - вроде это накладно, каждый раз пересчитывается размер массива.
m_count=m_pTcpSocket->bytesAvailable()+m_count;
но m_pTcpSocket->bytesAvailable() равно 0 :(


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: Пантер от Январь 12, 2017, 12:17
Вызвать лишний раз QByteArray::size не страшно. Там вообще наверное инлайновый метод.


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: Old от Январь 12, 2017, 12:25
но m_pTcpSocket->bytesAvailable() равно 0 :(
Это вы после чтения вызываете? Конечно там 0 будет.

И не увидел у вас выкусывание уже обработанного пакета из m_buffer?


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: stix357 от Январь 12, 2017, 12:57
Это вы после чтения вызываете? Конечно там 0 будет.
Я полагал, что там все одно цикл чтения, пока пакеты бегут.

И не увидел у вас выкусывание уже обработанного пакета из m_buffer?
А это черновик пока (отдельная прога для тестирования) без выкусывания :) Еще в поток упихать надо.


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: Old от Январь 12, 2017, 13:01
Еще в поток упихать надо.
Зачем? Там долгая обработка пакета?


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: stix357 от Январь 12, 2017, 13:16
Еще в поток упихать надо.
Зачем? Там долгая обработка пакета?
Не, это модуль, который встраивается в основную программу.
И там в отдельном потоке приходят сигналы еще с 2-х устройств. Встроенные платы АЦП.
Одна стробирующие импульсы выдает по прохождению трубы в установке через каждые 50 мм.
А труба летит со скоростью 700 мм/сек.
А вторая плата АЦП температуру привода выдает.
И мне данные со своей части с ними увязать надо.


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: Пантер от Январь 12, 2017, 13:25
Еще в поток упихать надо.
Зачем? Там долгая обработка пакета?
Не, это модуль, который встраивается в основную программу.
И там в отдельном потоке приходят сигналы еще с 2-х устройств. Встроенные платы АЦП.
Одна стробирующие импульсы выдает по прохождению трубы в установке через каждые 50 мм.
А труба летит со скоростью 700 мм/сек.
А вторая плата АЦП температуру привода выдает.
И мне данные со своей части с ними увязать надо.
У меня есть прога для парсинга данных от автомобильных трекеров. Идет чтение бинарных данных из сокета, парсинг их, формирование xml и выдача его наружу. Одновременно обрабатывается сейчас до 3К трекеров - загрузка процессора меньше 10%. Да, ассинхронка с одним основным потоком. :) А данные трекеры шлют часто, пакетов по 10 в секунду может быть.


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: stix357 от Январь 12, 2017, 13:28
У меня есть прога для парсинга данных от автомобильных трекеров. Идет чтение бинарных данных из сокета, парсинг их, формирование xml и выдача его наружу. Одновременно обрабатывается сейчас до 3К трекеров - загрузка процессора меньше 10%. Да, ассинхронка с одним основным потоком. :) А данные трекеры шлют часто, пакетов по 10 в секунду может быть.
А тут еще надо параллельно график в Гуе для оператора выводить, по мере поступления данных. Вот и приходится с потоками возится.


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: Пантер от Январь 12, 2017, 13:30
У меня есть прога для парсинга данных от автомобильных трекеров. Идет чтение бинарных данных из сокета, парсинг их, формирование xml и выдача его наружу. Одновременно обрабатывается сейчас до 3К трекеров - загрузка процессора меньше 10%. Да, ассинхронка с одним основным потоком. :) А данные трекеры шлют часто, пакетов по 10 в секунду может быть.
А тут еще надо параллельно график в Гуе для оператора выводить, по мере поступления данных. Вот и приходится с потоками возится.
Тогда далаются 2 потока - в одном гуй живет, а в другом все общение с девайсами. И прячется все за каким-нибудь Фасадом.


Название: Re: QTCPSocket в отдельном потоке.
Отправлено: Пантер от Январь 12, 2017, 13:31
А еще можно разделить на гуй и сервис.