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