| 
 Название: Помогите с потоком пожалуйста
 Отправлено: Fregloin от Сентября 16, 2013,  15:38
 
 Набросал простейший клиент, в котором tcp сокет живет в наслелнике QThread. Вылетает через несколько секунд после начала работы на readAll() #ifndef CMYSOCKET_H#define CMYSOCKET_H
 
 #include <QThread>
 #include <QTcpSocket>
 #include <QTimer>
 
 class CMySocket : public QThread
 {
 Q_OBJECT
 
 QTcpSocket  *   fsocket;
 QTimer      *   frequestTimer;
 
 QString         fhost;
 quint16         fport;
 
 size_t          freceived;
 size_t          fguardSize;
 QByteArray      fcurrentData;
 
 protected:
 
 void    run();
 
 public:
 
 explicit CMySocket(QObject *parent = 0);
 ~CMySocket();
 
 inline  void    setHost(const QString & value)  {   fhost = value;  }
 inline  void    setPort(quint16 value)  {   fport = value;  }
 inline  const   QString &   host()  const   {   return  fhost;  }
 inline          quint16     port()  const   {   return  fport;  }
 
 signals:
 
 void    dataReceived(QString jsonString);
 void    guardSizeExceed();
 
 public slots:
 
 private slots:
 
 void    socket_connect();
 void    socket_disconnect();
 void    socket_error(QAbstractSocket::SocketError);
 void    socket_read();
 void    socket_cleanup();
 void    socket_send_request();
 };
 
 #endif // CMYSOCKET_H
 
#include "cmysocket.h"
 CMySocket::CMySocket(QObject *parent) :
 QThread(parent)
 {
 fsocket = NULL;
 frequestTimer = NULL;
 fhost = "127.0.0.1";
 fport = 50001;
 fguardSize = 10485760L;
 freceived = 0L;
 connect(this,SIGNAL(finished()),this,SLOT(socket_cleanup()));
 }
 
 CMySocket::~CMySocket()
 {
 socket_cleanup();
 }
 
 void CMySocket::socket_connect()
 {
 qDebug("connected %s:%d",qPrintable(fhost),fport);
 //frequestTimer->start(500);
 }
 
 void CMySocket::socket_disconnect()
 {
 //frequestTimer->stop();
 qDebug("disconnected %s:%d",qPrintable(fhost),fport);
 }
 
 void CMySocket::socket_error(QAbstractSocket::SocketError)
 {
 qDebug("error %s:%d %s",qPrintable(fhost),fport,qPrintable(fsocket->errorString()));
 }
 
 void CMySocket::socket_read()
 {
 int bytesAvail = fsocket->bytesAvailable();
 if(bytesAvail<=0) return;
 QByteArray  packetData = fsocket->readAll();    //считываем текущую часть принятых данных
 
 qDebug("read %d bytes",packetData.size());
 
 /*
 if(!packetData.isEmpty())                       //если что то есть(а полюбому что то должно быть)
 {
 int terminatorIndex;                        //индекс терминатора (нулевого символа)
 int prevTerminatorIndex = 0;                //предыдущий терминатор
 int dataSize = packetData.size();           //размер полученных данных
 
 terminatorIndex = packetData.indexOf('\0',prevTerminatorIndex); //ищем первый терминатор в пакете
 if(terminatorIndex<0)                       //если нет терминатора, копируем целиком
 {
 fcurrentData.append(packetData);        //добавляем полученные данные во временную строку
 freceived+=dataSize;                    //инкрементируем счетчик полученных данных
 if(freceived>=fguardSize)               //если полученных данных больше чем охранный размер
 {
 freceived = 0L;                      //обнуляем счетчик принятых данных
 qDebug("freceived %lu",freceived);
 emit guardSizeExceed();             //сигналим об ошибке
 }
 return;
 }
 
 int last;
 
 while(terminatorIndex>=0 && prevTerminatorIndex<dataSize)
 {
 last = terminatorIndex-prevTerminatorIndex;
 if(last>0)
 {
 fcurrentData.append(packetData.mid(prevTerminatorIndex,last)); //копируем часть до терминатора
 emit dataReceived(QString(fcurrentData));  //сигналим об очередной строке с json
 }
 freceived = 0L;
 qDebug("freceived %lu",freceived);
 fcurrentData.clear();                           //стираем временный буфер
 prevTerminatorIndex = terminatorIndex+1;        //сдвигаем указатель, с которого будем искать следующий терминатор
 terminatorIndex = packetData.indexOf('\0',prevTerminatorIndex);
 }
 
 if(prevTerminatorIndex<dataSize)    //если осталась часть принятых данных со следующей json строки
 {
 int lastPart = dataSize-prevTerminatorIndex;
 fcurrentData.append(packetData.mid(prevTerminatorIndex,(lastPart)));//копируем остаток
 freceived+=lastPart;
 qDebug("freceived %lu",freceived);
 }
 }
 */
 }
 
 void CMySocket::socket_cleanup()
 {
 if(frequestTimer)
 {
 frequestTimer->stop();
 frequestTimer->deleteLater();
 frequestTimer = NULL;
 }
 if(fsocket)
 {
 fsocket->disconnectFromHost();
 fsocket->deleteLater();
 fsocket = NULL;
 }
 }
 
 void CMySocket::socket_send_request()
 {
 }
 
 void CMySocket::run()
 {
 if(fhost.isEmpty() || !fport)
 exit(-1);
 
 //frequestTimer = new QTimer;
 //connect(frequestTimer,SIGNAL(timeout()),this,SLOT(socket_send_request()));
 fsocket = new QTcpSocket;
 connect(fsocket,SIGNAL(connected()),this,SLOT(socket_connect()));
 connect(fsocket,SIGNAL(disconnected()),this,SLOT(socket_disconnect()));
 connect(fsocket,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(socket_error(QAbstractSocket::SocketError)));
 connect(fsocket,SIGNAL(readyRead()),this,SLOT(socket_read()));
 fsocket->connectToHost(fhost,fport);
 exec();
 }
 
основное окно #include "mainwindow.h"#include "ui_mainwindow.h"
 
 MainWindow::MainWindow(QWidget *parent) :
 QMainWindow(parent),
 ui(new Ui::MainWindow)
 {
 ui->setupUi(this);
 
 QMenu   *   menu = new QMenu(trUtf8("Связь"));
 QAction *   action = menu->addAction(trUtf8("Подключиться"));
 connect(action,SIGNAL(triggered()),this,SLOT(connect_sockets()));
 action = menu->addAction(trUtf8("Отключиться"));
 connect(action,SIGNAL(triggered()),this,SLOT(disconnect_sockets()));
 
 menuBar()->addMenu(menu);
 
 
 fsocket = new CMySocket(this);
 }
 
 MainWindow::~MainWindow()
 {
 delete ui;
 }
 
 void MainWindow::connect_sockets()
 {
 fsocket->setHost("192.168.1.101");
 fsocket->setPort(50002);
 connect(fsocket,SIGNAL(dataReceived(QString)),this,SLOT(process_data(QString)));
 if(!fsocket->isRunning())
 {
 fsocket->start();
 }
 }
 
 void MainWindow::disconnect_sockets()
 {
 if(fsocket->isRunning())
 {
 fsocket->quit();
 fsocket->wait();
 }
 }
 
 void MainWindow::process_data(const QString &value)
 {
 //qDebug("data %s",qPrintable(value));
 }
 
По сути это вырожденный сетевой клиент, который работал раньше (но нужно довести до ума). Почему у меня вылетает при чтении с сокета. В консоли ругани на принадлежность к разным объектам нет.
 Название: Re: Помогите с потоком пожалуйста
 Отправлено: Fregloin от Сентября 16, 2013,  15:51
 
 Добавил вывод инфы, кто где запускается, и вот что имеем: CMySocket::CMySocket(QObject *parent) :QThread(parent)
 {
 fsocket = NULL;
 frequestTimer = NULL;
 fhost = "127.0.0.1";
 fport = 50001;
 fguardSize = 10485760L;
 freceived = 0L;
 connect(this,SIGNAL(finished()),this,SLOT(socket_cleanup()));
 qDebug("CMySocket lives in %p, currentThread %p",this->thread(),currentThread());
 }
 
 CMySocket::~CMySocket()
 {
 socket_cleanup();
 }
 
 void CMySocket::socket_connect()
 {
 qDebug("connected %s:%d",qPrintable(fhost),fport);
 frequestTimer->start(500);
 }
 
 void CMySocket::socket_disconnect()
 {
 frequestTimer->stop();
 qDebug("disconnected %s:%d",qPrintable(fhost),fport);
 }
 
 void CMySocket::socket_error(QAbstractSocket::SocketError)
 {
 qDebug("error %s:%d %s",qPrintable(fhost),fport,qPrintable(fsocket->errorString()));
 }
 
 void CMySocket::socket_read()
 {
 qDebug("CMySocket::socket_read() %p",currentThread());
 int bytesAvail = fsocket->bytesAvailable();
 if(bytesAvail<=0) return;
 QByteArray  packetData = fsocket->readAll();    //считываем текущую часть принятых данных
 qDebug("read %d bytes",packetData.size());
 }
 
 void CMySocket::socket_cleanup()
 {
 if(frequestTimer)
 {
 frequestTimer->stop();
 frequestTimer->deleteLater();
 frequestTimer = NULL;
 }
 if(fsocket)
 {
 fsocket->disconnectFromHost();
 fsocket->deleteLater();
 fsocket = NULL;
 }
 }
 
 void CMySocket::socket_send_request()
 {
 }
 
 void CMySocket::run()
 {
 if(fhost.isEmpty() || !fport)
 exit(-1);
 
 frequestTimer = new QTimer;
 connect(frequestTimer,SIGNAL(timeout()),this,SLOT(socket_send_request()));
 fsocket = new QTcpSocket;
 connect(fsocket,SIGNAL(connected()),this,SLOT(socket_connect()));
 connect(fsocket,SIGNAL(disconnected()),this,SLOT(socket_disconnect()));
 connect(fsocket,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(socket_error(QAbstractSocket::SocketError)));
 connect(fsocket,SIGNAL(readyRead()),this,SLOT(socket_read()));
 fsocket->connectToHost(fhost,fport);
 qDebug("CMySocket::run() current thread %p, socket in %p",this->currentThread(),fsocket->thread());
 exec();
 }
 
вывод отладчика CMySocket lives in 0x2083f10, currentThread 0x2083f10
 CMySocket::run() current thread 0x23bf130, socket in 0x23bf130
 connected 192.168.1.101:50002
 CMySocket::socket_read() 0x2083f10
 read 373 bytes
 CMySocket::socket_read() 0x2083f10
 read 373 bytes
 CMySocket::socket_read() 0x2083f10
 read 373 bytes
 
 получается, что сокет создается в отдельном потоке, но слоты вызываются в потоке, в котором создан CMySocket. А как мне сделать, что бы слоты вызывались в том, потоке, в котром живет сокет??
 Название: Re: Помогите с потоком пожалуйста
 Отправлено: mutineer от Сентября 16, 2013,  15:54
 
 Не наследоваться от QThread, а создать отдельный объект со слотами и всем прочим. Создать QThread, запустить его, а затем мувнуть объект в тред 
 Название: Re: Помогите с потоком пожалуйста
 Отправлено: Bepec от Сентября 16, 2013,  15:55
 
  в конструкторе потока спасёт вас. PS и если можно, дублируйте код в архиве - на форуме довольно неудобно его просматривать. update: Ответы mutineer и меня - два различных способа решения этой проблемы.  PS равнозначных способа ^.^
 Название: Re: Помогите с потоком пожалуйста
 Отправлено: mutineer от Сентября 16, 2013,  16:04
 
 PS равнозначных способа ^.^
 ну да, вопрос религии:)
 Название: Re: Помогите с потоком пожалуйста
 Отправлено: Fregloin от Сентября 16, 2013,  16:05
 
 Не наследоваться от QThread, а создать отдельный объект со слотами и всем прочим. Создать QThread, запустить его, а затем мувнуть объект в тред
 Так тоже делал, но при завершении потока через quit() он звисал, wait() выдавал ошибку завершения потока...
 Название: Re: Помогите с потоком пожалуйста
 Отправлено: Fregloin от Сентября 16, 2013,  19:04
 
 Сделал по другому: #include <QThread>#include "qdspclient.h"
 
 class QDspClientThread : public QThread
 {
 Q_OBJECT
 
 public:
 explicit QDspClientThread(QObject *parent = 0);
 ~QDspClientThread();
 QDspClient  *   dspClient;
 
 };
 
QDspClientThread::QDspClientThread(QObject *parent) :QThread(parent)
 {
 dspClient = new QDspClient;
 connect(this,SIGNAL(started()),dspClient,SLOT(connectToServer()));
 connect(this,SIGNAL(finished()),dspClient,SLOT(disconnectFromServer()));
 }
 
 QDspClientThread::~QDspClientThread()
 {
 dspClient->deleteLater();
 }
 
Вот как использую void    CDspHandler::startClient(){
 foreach(QDspClientThread * clientThread, fdspConnections)
 {
 if(!clientThread->isRunning())
 {
 if(clientThread->dspClient->connectionConfig().interfaceIndex()>=0)
 {
 clientThread->start();
 clientThread->dspClient->moveToThread(clientThread->currentThread());
 }
 }
 }
 
 emit    sourceChanged(NULL);
 }
 
 void    CDspHandler::stopClient()
 {
 foreach (QDspClientThread   *   clientThread, fdspConnections)
 {
 if(clientThread->isRunning())
 {
 qDebug("quiting thread for %s:%d",qPrintable(clientThread->dspClient->connectionConfig().host()),clientThread->dspClient->connectionConfig().port());
 clientThread->quit();
 bool result = clientThread->wait(5000);
 qDebug(result?"Ok":"Failed");
 clientThread->dspClient->moveToThread(thread());
 }
 }
 }
 
На потоки не ругается, но зависает на void     QRawClient::connectToServer(){
 fmustReconnect = true;
 if(fsocket.state() != QAbstractSocket::UnconnectedState) return;
 
 int fd = fsocket.socketDescriptor();
 if(fd<0)
 {
 fd = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
 }
 
 if(!fbindAddress.isNull())   //если биндинг задан, создаем сокет посредством Qt
 {
 //      qDebug("Try bind %i:%s to %s",connectionConfig().interfaceIndex(),qPrintable(connectionConfig().host()),qPrintable(fbindAddress.toString()));
 
 struct sockaddr_in bindAddr;
 
 memset(&bindAddr,0,sizeof(bindAddr));
 bindAddr.sin_family = PF_INET;
 bindAddr.sin_addr.s_addr = htonl(fbindAddress.toIPv4Address());
 
 if(bind(fd,(const struct sockaddr *)&bindAddr,sizeof(bindAddr))!=0)
 {
 qDebug("Socket bind to %s failed with reason %s",qPrintable(fbindAddress.toString()),strerror(errno));
 shutdown(fd,2);
 #ifdef Q_WS_WIN32
 closesocket(fd);
 #else
 close(fd);
 #endif
 onDisconnected();
 return;
 }
 }
 
 struct sockaddr_in connect_addr;
 memset(&connect_addr,0,sizeof(connect_addr));
 connect_addr.sin_family = PF_INET;
 connect_addr.sin_port = htons(connectionConfig().port());
 
 QHostAddress address(connectionConfig().host());
 connect_addr.sin_addr.s_addr = htonl(address.toIPv4Address());
 
 if(::connect(fd,(const struct sockaddr *)&connect_addr,sizeof(connect_addr))==-1) //<<<<<ЗДЕСЬ ЗАВИСАЕТ
 {
 qDebug("connect error! %s",strerror(errno));
 close(fd);
 onDisconnected();
 return;
 }
 else
 {
 if(!fsocket.setSocketDescriptor(fd,QAbstractSocket::ConnectedState))
 qDebug("binding to native socket failed");
 onConnected();
 }
 }
 
 Название: Re: Помогите с потоком пожалуйста
 Отправлено: Bepec от Сентября 17, 2013,  08:02
 
  в конструкторе потока спасёт вас. PS и если можно, дублируйте код в архиве - на форуме довольно неудобно его просматривать. update: Ответы mutineer и меня - два различных способа решения этой проблемы.  PS равнозначных способа ^.^PS интересно, научатся ли люди читать все комментарии, а не через один? :)
 Название: Re: Помогите с потоком пожалуйста
 Отправлено: Fregloin от Сентября 17, 2013,  09:04
 
 думаете я не делал, как было указано выше? Если бы заработало, я бы тут уже не спрашивал. Но увы, в упор виснет на connect(scoket).
 
 Название: Re: Помогите с потоком пожалуйста
 Отправлено: Bepec от Сентября 17, 2013,  09:32
 
 Но никакого коммента вы не выделили мне :) И в коде не видно ни одной такой строки :)
 Выкидывайте проект в архиве, если осмелитесь - разберёмся.
 
 Название: Re: Помогите с потоком пожалуйста
 Отправлено: Fregloin от Сентября 17, 2013,  15:50
 
 вырезаю все что связано с моими сокетами (надеюсь на ваши советы по поводу их улучшения)
 
 Название: Re: Помогите с потоком пожалуйста
 Отправлено: Bepec от Сентября 17, 2013,  17:14
 
 Ну зачем вы, создатели тем, так меня мучаете? 
 Или это уже привычка - просят проект - кинем пару обрезанных файлов. Просят архив - кинем половину. Хотим полный скриншот - на те вам скриншот активного окна :D
 
 PS :)
 
 Название: Re: Помогите с потоком пожалуйста
 Отправлено: Fregloin от Сентября 18, 2013,  10:37
 
 ответ банален, это коммерческий проект, который я не могу просто вязть и выложить на обозрение всем.мне нужна помощь. я понимаю что из обрезков целая картина врядли получится, но исходники выкладыватьс здесь я категорически не могу. думаю Вы бы тоже так не делали.
 
 Название: Re: Помогите с потоком пожалуйста
 Отправлено: Bepec от Сентября 18, 2013,  11:40
 
 Вы всегда можете взять, сесть и в пустой проект добавить ваши классы и сделать минимально работоспособный проект. Он будет делать тупо проверку. И это для вас - дело пяти минут. Для других - нужно понять взаимосвязи и назначение ваших классов, как то их присобачить друг с другом, заставить скомпилироваться и задуматься - а что же должно быть в результате? 
 
 |