Добрый день уважаемые. Я новичок в qt да и в c++ поэтому бейте меня и посылайте на RTFM.
Есть Вот такой код
QString M_class::ReadSocket()
{
QTime TimeOut;
TimeOut.start();
while(!socket.waitForReadyRead())
{
QCoreApplication::processEvents();
if(TimeOut.elapsed()>=6000)
{
return(0);
}
}
return(socket.readAll());
}
dasV,
что мешает включить в конольную прогу Q_OBJECT ???
и использовать для чтения сокета сигналы и слоты тогда можно.
dasV, цыклы лучше в отдельный поток помещать у них приоритет задать можно.
virtual bool waitForReadyRead ( int msecs = 30000 )
Как ты думаешь...А зачем там задан параметр msecs ?
Хм, написал вот что
QString Sms_class::ReadSocket()
{
QTextCodec::setCodecForTr(QTextCodec::codecForName("CP-1251"));
QTextCodec *concodec = QTextCodec::codecForName("CP-866");
QTextStream out(stdout);
out.setCodec(concodec);
QTime TimeOut;
TimeOut.start();
if(socket.waitForReadyRead(60000)==false)
{ out<<"MSG : Time - "<<TimeOut.elapsed()<<endl;
return(0);
}
out<<"MSG : Time - "<<TimeOut.elapsed()<<endl;
return(socket.readAll());
}
tmp=ReadSocket();
if(tmp.isNull ()==true)
{
out<<"MSG : Error CloseSession!!"<<tmp<<endl;
return(false);
}
QString QIODevice::errorString () const ?
Кто должен отлаживать, ты или МЫ?
А я и не говорил что нельзя, мне просто неудобно, из за непонимания логики работы программы при использовании слотов.
Мне необходимо допустим три раза вызвать запись, три раза прочитать и при этом каждый раз я получаю разные данные, которые необходимо обработать разными методами. В результате я не понимаю, что мне надо делать в при вызове слота readyRead, откуда вызвано, куда что передавать,… понятно когда GUI приложение, жмякнул на кнпку (соединится) я соединился, жмякнул на кпопку (Послать) я и послал, жмякнул выход я рас соединился.
А в консоли, что мне делать?? Я все и по порядку и делаю, при этом смысла в слотах я не вижу.
2_LE0N спасибо, буду думать..
2_Litkevich Yuriy спасибо за замечание, буду отвыкать.
С уважением
dasV,
с этого надо было начинать.
давай задачу поконкретнее и все будет ок. в конце концов примеров куча.
Задача такова, я должен послать на сервер запрос авторизации, сервер мне ответит (тут я должен распарсить что он мне ответил) если это нормальный ответ, я посылаю запрос на выдачу мне нужной информации, при этом сервер мне отвечает xml строкой где я ищу нужные мне строки, вывожу на экран и опять посылаю запрос на закрытие соединения, опять ответ опять корректно закрыли или нет. Это простейший случай который реализован без Q_OBJECT шаг за шагом.
В результате я не могу понять ну вот я в конструкторе или в другом месте создал
QObject::connect(&socket, SIGNAL(encrypted()),this, SLOT(socketEncrypted()));
QObject::connect(&socket, SIGNAL(readyRead()),this, SLOT(socketReadyRead()));
set_encrypted_connect(); //socket.connectToHostEncrypted(ssl_host,ssl_port);
socket.write(get.toUtf8()+ "\r\n"); //тут get="GET что то там ";
dasV,
существует такой метод или "агрегат" униерсальный для таих задач. называется машина состояний.
есть состояния твоей проги. есть состояния сокета есть состояния данных и т.д и т.п..
состояния это обычно перечисляемый тип. и переменная в классе. в зависимости от действий в программе переключай состояния. при событиях проверяй в каком состоянии находишься и действуй.
2_ kwisp Спасибо, буду думать, а это не оно ли случаем?
http://ru.wikipedia.org/wiki/Автоматное_программирование
Насчет, почему вызовется, потому как мы сделали socket.write при этом сервер нам будет возвращать данные, чего мы и ожидаем, ну по крайней мере в примерах именно так реализовано.
Доброго времени суток уважаемые.
Сделал как и сказано было, однако возникла проблема, если первый раз я произвожу запись из функции socketEncrypted() после чего читаю вполне нормально данные полученные от сервера, то второй раз, данные записать не удается. Точнее функция возвращает мне количество записанных данных, однако на деле ничего на сервер не приходит.
Может кто то сталкивался с такой проблемой?
void ssl_class::socketReadyRead()
{
QString tmp;
bool ok;
int i; // он вообще то не оч нужен, но так..пусть будет =)
switch(state)
{
case StartSession:
{
tmp=xmlParser(socket.readAll());
SessionID=tmp.toInt(&ok, 10);
if(!ok)
{
if(SessionID<=0)
{
//MSG : ошибка логин или пароль, не верны
emit finish();
}
}
tmp="GET "+get+"/CloseSession?SessionID="+ QString::number(SessionID)+" \r\n";
i = socket.write(tmp.toUtf8());
if(i==-1)
{
//MSG : Ошибка при записи
}
else
{
//MSG : записали много байт
}
state=CloseSession;
break;
}
case CloseSession:
{
tmp=xmlParser(socket.readAll());
SessionID=tmp.toInt(&ok, 10);
if(!ok)
{
if(SessionID==0)
{
//MSG : все хорошо
}
}
emit finish();
break;
}
}
}
Может я уже немного не в тему и не вовремя, но я бы использовал другую конструкцию. Предлогалось уже использовать сигналы и слоты, так и не понял почему этого не сделали. Я бы использовал следущую конструкцию:
Создал свой класс, наследник от QThread: class ThreadSocket : public QThread
{
Q_OBJECT
...
QTcpSocket *socket;
QMutex mutex;
QWaitCondition cond;
QByteArray DataIn;
...
protected:
void run();
...
private slots:
void readSocket();
...
}
Переопредилил Run следущим образом:void ThreadSocket::run()
{
const int Timeout = 6 * 1000;
emit SendServer("first_command"); // отправляем данные для записи в соккет
mutex.lock();
if ( cond.wait(&mutex, Timeout) ) { // ожидаем ответ. Если получили, разбираем данные и отправляем след. команду
... // разбираем данные, в общем любые требуемые действия.
DataIn.clear();
emit SendServer("second_command"); // отправляем данные для записи в соккет
if ( cond.wait(&mutex, Timeout) ) {// ожидаем ответ.
... // разбираем данные, в общем любые требуемые действия.
DataIn.clear();
// и т.д.
...
...
...
...
} else {
emit displayMessage("Timeout №2"); // отправляем сообщение об ошибке.
}
} else {
emit displayMessage("Timeout №1"); // отправляем сообщение об ошибке.
}
mutex.unlock();
...
}
SLOT. Чтение динных с сервера:void ThreadSocket::readSocket()
{
if ( socket->canReadLine() ) {
mutex.lock(); // -----------------------
DataIn = DataIn + socket.readAll();// | mutex здесь впринципе не нужен )))
mutex.unlock(); //-----------------------
cond.wakeOne();
}
}
Надеюсь мысль понятна
[offtop]
Простите, но почему я не могу редактировать сообщения?
И как сделать Раскрывающийся текст. А то я обрамил все в тег "Скрытый текст", думал что это оно, теперь и не знаю, читается ли код?
[\offtop]
Дополнительно(конкретно по вопроссу)
socket.flush();
И еще. Сигнал readyRead () испускается каждый раз, как доступны новые данные для чтения. Увырены ли Вы, делая socket.readAll() , что все данные которые Вы ожидаете доступны для чтения. Лучьше всегда делать проверку, например функцией bytesAvailable () или canReadLine ().
Litkevich Yuriy Спасибо. С раскрывающимся текстом разобрался, просто был невнимателен. А с редактированием это плохо, жесткие у вас правила.
Всем спасибо за ответы.
Сделал socket.flush (); однако ничего не изменилось. Решил посмотреть состояние socket и выяснилось, что оно все время QAbstractSocket::ConnectedState то есть вроде как ошибок и нет, правда если после socket.write сделать socket.flush (); то состояние меняется на QAbstractSocket::UnconnectedState, вообще не понятно ничего =(
Так же подумал, что мол не все прочитали и пишем, поэтому сделал так
out<<socket.bytesAvailable()<<endl;
tmp=xmlParser(socket.readAll());
out<<socket.bytesAvailable()<<endl;
Добрый день уважаемые, только что вернулся из анабиоза.
igor_bogomolov я сделал (точнее попытался сделать) как Вы и сказали через canReadLine() однако столкнулся с недопониманием (не докурил) вот какого момента (информацию о котором не смог найти).
Скажите если мы не можем прочитать строку, это может значить что мы прочитали все что нам прислали?
То есть нам надо определить, или мы действительно не можем прочитать строку (а значит, нам надо бы подождать) или второй вариант, нам уже все прислали и надо обрабатывать строки?
Вторая проблема вытекающая из первой, с которой столкнулся, это то, что на последнюю строку canReadLine() выдает false, хотя если вызывать принудительно ReadLine() выдает последнюю строку... не понятно так как если подождать, socketReadyRead() повторно не вызывается =(.
Спасибо.
У вас хоть какой-то протокол общения с сервером есть? Не возвращается ли в самом начале сколько байт будет передано? Или завершающая последовательность какая-нибудь есть? Или вы отправляете команду и сервер начинает сыпать неизвестно чего и сколько
// add
Можно убрать проверку canReadLine, и считывать все что приходит в буфер. При этом должен быть какой-то таймаут. Если в течении этого таймаута ничего не пришло, то считаем что все данные получены, и идем на оьработку
Добрый день.
Протокол общения обычный http, я знаю, сколько мне передадут или должны передать (так как есть Content-Length: который я обрабатываю) и получаю длину, которую пока не обрабатываю.
Но это все ерунда полная (хотя и интересная), мне важно узнать, по какой причине socket не пишет на сервер второй раз =(
Спасибо.
Да я действительно не очень…ммм, не очень корректно написал.
Проблема моей программы (и соответственно моей безграмотности) заключается в том, что в случае повторной отсылки GET запроса на сервер (state == CloseSession) , ничего не происходит, то есть запрос просто не передается!
qlonglong ssl_class::WriteMsgToSrv()
{
QString tmp; //не обязательно, убрать.
qlonglong i; //не обязательно, убрать.
switch(state)
{
case(StartSession):
{
tmp="GET "+get+"/StartSession?Login="+login+"&Password="+password+"&Gmt=3 \r\n";
break;
}
case(CloseSession):
{
tmp="GET "+get+"/CloseSession?SessionID="+ QString::number(SessionID)+" \r\n";
break;
}
}
i= socket.write( tmp.toUtf8() );
socket.flush ();
return( i );
}
Приложите еще хотябы код метода в котором вы считываете данные с соккета.
То же самое, к сожалению, результат вывода примерно следующий
Первый раз
QAbstractSocket::ConnectedState
"Unknown error"
MSG : Connected State is = 3
//i= socket.write( tmp.toUtf8() ) ;
//socket.flush ();
MSG : Connected State is = 3
Второй раз
QAbstractSocket::ConnectedState
"Unknown error"
MSG : Connected State is = 3
//i= socket.write( tmp.toUtf8() ) ;
//socket.flush ();
MSG : Connected State is = 3
qlonglong ssl_class::WriteMsgToSrv()
{
QString tmp;
qlonglong i;
switch(state)
{
case(StartSession):
{
tmp="GET "+get+"/StartSession?Login="+login+"&Password="+password+"&Gmt=3 \r\n";
break;
}
case(CloseSession):
{
tmp="GET "+get+"/CloseSession?SessionID="+ QString::number(SessionID)+" \r\n";
break;
}
}
qDebug() << socket.state();
qDebug() << socket.errorString ();
emit displayMessage("MSG : Connected State is = " + QString::number( QAbstractSocket::ConnectedState) );
i= socket.write( tmp.toUtf8() );
socket.flush ();
emit displayMessage("MSG : Connected State is = " + QString::number( QAbstractSocket::ConnectedState) );
return( i );
}
Похоже, что так оно и есть, после получения данных и повторной попытки записи, не происходит закрытие socket, видимо его принудительно надо закрывать, так как это ssl соединении а работаем мы с http.
Сейчас проверил, что выдает socket.waitForReadyRead(60000) “не пугайтесь это из моего гениального творения, без слотов =)” при попытке повторного чтения, и выяснил что
waitForReadyRead QAbstractSocket::UnconnectedState
waitForReadyRead "Remote host closed"
QString Sms_class::ReadSocket()
{
out<<"MSG : Open Mode " <<socket.openMode ()<<endl;
if(!socket.waitForReadyRead(60000))
{
qDebug() <<"waitForReadyRead"<< socket.state();
qDebug() <<"waitForReadyRead"<< socket.errorString ();
return(0);
}
return(socket.readAll());
}
Форум Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)