Russian Qt Forum

Qt => Общие вопросы => Тема начата: G-virus от Апрель 26, 2010, 23:16



Название: Непонятная проблема с приемом данных int в QTcpSocket
Отправлено: G-virus от Апрель 26, 2010, 23:16
Всем привет. Столкнулся с такой проблемой и никак не могу найти объяснения. Есть сервер, к которому подключается клиент. И одна из функций, передача данных с QDAtaStream. Данные передаются так, сначала передается длина файла (в это время на клиенте принимается эта длина, и запускается for от 0 до длины. И по одному символу передаются байты файла. Вот кусок функции приема данных на клиенте:
Код
C++ (Qt)
msger >> end;
//QMessageBox::information(NULL, "", "", 0, 0);
       if (end != 0){
       files = fopen(buf2.toAscii(), "wb"); //решил воспользоваться стандартными Си-шными методами записи файла
       for (i = 0; i < end; i++)
       {
           msger >> chr;
           putc(chr, files);
       }
       fclose(files);
 

Вопрос такой: Если закомментить тот совершенно ненужный месседжбокс, то при пробегании цикла после пары килобайт файла начинают приниматься одни нули в переменнную chr. Если оставить месседжбокс, то все отлично принимается и записывается. Объясните пожалуйста, почему так, и можно ли как-то избавиться от зависимости от месседжбокса?


Название: Re: Непонятная проблема с приемом данных int в QTcpSocket
Отправлено: registrationfedser87 от Апрель 27, 2010, 07:36
Может быть на стороне клиента байты, пересылаемые сервером, успевают получаться(и вообще сервер уже успел отправить необходимые клиенту в данный момент байты)? Вызываешь ли ты flush у сервера? И вообще, по мне так подход к получению и отправке неверный. Посмотри кутешные примеры по QTcpSocket.


Название: Re: Непонятная проблема с приемом данных int в QTcpSocket
Отправлено: G-virus от Апрель 27, 2010, 15:43
Может быть на стороне клиента байты, пересылаемые сервером, успевают получаться(и вообще сервер уже успел отправить необходимые клиенту в данный момент байты)? Вызываешь ли ты flush у сервера? И вообще, по мне так подход к получению и отправке неверный. Посмотри кутешные примеры по QTcpSocket.

нет. flush-а нету. С месседжбоксом все правильно ведь работает, при чем тут flush :) И почему не правильно?


Название: Re: Непонятная проблема с приемом данных int в QTcpSocket
Отправлено: registrationfedser87 от Апрель 27, 2010, 16:02
вызов TCPSocket.flush() на стороне сервера немедленно отправляет данные.
Почему мне кажется неправильно(может я и ошибаюсь конечно)-потому что передача идёт пакетами, и если ты скажем передаёшь 10 мегабайт это не значит что они у тебя придут одним пакетом. Т.е. тебе по кусочкам надо собирать необходимый пакет. Как пакет набран-тогда и обрабатываешь(т.е. ты допустим передаёшь сначала длину файла, и когда приходят куски пакетов ты их добавляешь в результирующий выходной файл пока не получишь все байты).


Название: Re: Непонятная проблема с приемом данных int в QTcpSocket
Отправлено: garryHotDog от Апрель 27, 2010, 16:41
по flush() написано правильно....а еще есть такая штука как алгоритм "Нагла"


Название: Re: Непонятная проблема с приемом данных int в QTcpSocket
Отправлено: G-virus от Апрель 27, 2010, 17:53
Т.е. тебе по кусочкам надо собирать необходимый пакет. Как пакет набран-тогда и обрабатываешь(т.е. ты допустим передаёшь сначала длину файла, и когда приходят куски пакетов ты их добавляешь в результирующий выходной файл пока не получишь все байты).

Я в принципе так и делаю :) по одному символу передаю и принимаю и пишу сразу :)

Насчет flush():

У меня цикл отправки на сервере выглядит аналогично
Код
C++ (Qt)
while ((ch = getc(file)) != EOF)
 out << ch;
 
flush() надо после out сразу добавлять, так ведь?
То есть вот так
Код
C++ (Qt)
while ((ch = getc(file)) != EOF)
{
 out << ch;
 socket->flush();
}
 


Название: Re: Непонятная проблема с приемом данных int в QTcpSocket
Отправлено: crossly от Апрель 27, 2010, 18:09
данные пишутся по сигналу readyRead() ??


Название: Re: Непонятная проблема с приемом данных int в QTcpSocket
Отправлено: G-virus от Апрель 27, 2010, 19:24
данные пишутся по сигналу readyRead() ??

Нет. Я же прислал. В цикле. Ну там как, приходит строка, вызывается сигнал readyRead(). И от этого срабатывает слот, в котором вызывает функция, содержащая тот самый цикл

fedser87
 Добавил flush(). Толку - 0. Только начинаются лаги, приходит лишняя информация на клиент, а результат один и тот же


Название: Re: Непонятная проблема с приемом данных int в QTcpSocket
Отправлено: registrationfedser87 от Апрель 28, 2010, 08:04
Проблема в том, что сигнал readyRead() у тебя не обязательно вызовется только 1 раз (я писал выше-вс зависит от того на сколько пакетов разобъются твои данные). Т.е. этот сигнал может вызваться раз 10, и каждый раз могут приходить разные по размеру данные. Посмотри примеры кутешные  Fortune Server Example, Fortune Client Example, Blocking Fortune Client Example. Если тебя напрягает то что несколько раз будут вызываться слоты, то посмотри внимательнее пример Blocking Fortune Client Example-там как раз всё в одном методе обрабатывается, привожу кусок кода с примера:
Код
C++ (Qt)
        quint16 blockSize;
        QDataStream in(&socket);
        in.setVersion(QDataStream::Qt_4_0);
        in >> blockSize;
 
        while (socket.bytesAvailable() < blockSize) {
            if (!socket.waitForReadyRead(Timeout)) {
                emit error(socket.error(), socket.errorString());
                return;
            }
        }
 


Название: Re: Непонятная проблема с приемом данных int в QTcpSocket
Отправлено: crossly от Апрель 28, 2010, 12:06
об этом я и говорю.... :)


Название: Re: Непонятная проблема с приемом данных int в QTcpSocket
Отправлено: G-virus от Апрель 28, 2010, 19:43
привожу кусок кода с примера:

То есть я должен прислать размер файла (что я в общем-то и делаю) а потом перед и после цикла приема файла поместить этот цикл, который Вы мне прислали так?


Название: Re: Непонятная проблема с приемом данных int в QTcpSocket
Отправлено: registrationfedser87 от Апрель 29, 2010, 07:40
Нет. Кусок я для примера привёл(хотел показать что надо ожидать получение необходимых байт). Ещё раз повторю, как писал crossly, тебе надо привязаться к сигналу readyRead() (чтобы не блокировать приложение в ожидании данных-это если у тебя неконсольное приложение), т.е. как приходит часть пакета, то срабатывает сигнал.
Алгоритм такой:
1. Получили размер файла и записали например в переменную fileSize, обнулили переменную currentFileSize (она будет показывать сколько байт мы получили);
2. Теперь каждый раз когда нам приходят байты, мы увеличиваем переменную currentFileSize на кол-во полученных байт(пусть скажем сейчас например получили X байт, мы увеличиваем currentFileSize+=X) и добавляем полученные байты в выходной файл и проверяем, достиг ли файл необходимого размера (точнее проверяем currentFileSize>=fileSize), если достиг,то заканчиваем приём файла.


Название: Re: Непонятная проблема с приемом данных int в QTcpSocket
Отправлено: G-virus от Апрель 29, 2010, 15:54
Нет. Кусок я для примера привёл(хотел показать что надо ожидать получение необходимых байт). Ещё раз повторю, как писал crossly, тебе надо привязаться к сигналу readyRead() (чтобы не блокировать приложение в ожидании данных-это если у тебя неконсольное приложение), т.е. как приходит часть пакета, то срабатывает сигнал.
Алгоритм такой:
1. Получили размер файла и записали например в переменную fileSize, обнулили переменную currentFileSize (она будет показывать сколько байт мы получили);
2. Теперь каждый раз когда нам приходят байты, мы увеличиваем переменную currentFileSize на кол-во полученных байт(пусть скажем сейчас например получили X байт, мы увеличиваем currentFileSize+=X) и добавляем полученные байты в выходной файл и проверяем, достиг ли файл необходимого размера (точнее проверяем currentFileSize>=fileSize), если достиг,то заканчиваем приём файла.

А я вот подумал сделать так. У меня в принципе на клиент приходят комбинированные строки. Если в ней есть идентификатор set то срабатывает такая-то функция. Правильно ли будет создать класс с наследованием QThread, в нем функцию run(). И допустим, если в строке есть set, то раньше запускалась функция setGetFile(). Если теперь я вместо этой функции вызову Thread->start(); а в функции run() сделаю вызов setGetFile(), это поможет?

И по поводу сигнала. У меня просто на этот сигнал привязана функция, которая обрабатывает пришедшую строку и вызывает соответствующую функцию. Как не хотелось бы все приходящие данные пихать в файл :)


Название: Re: Непонятная проблема с приемом данных int в QTcpSocket
Отправлено: G-virus от Май 01, 2010, 14:26
fedser87, сделал, как Вы сказали. Только все равно программа зацикливается.
Вот функции:
функция-слот на сигнале readyRead()
Код
C++ (Qt)
void MainWindow::getDataStream()
{
   buf1 = ""; swt = "";
   buf2 = ""; buf3 = "";
   ch = "";
   QDataStream in(&socket);
   QDataStream out(&socket);
   in.setVersion(QDataStream::Qt_4_6);
   if (fileSize != end)
      getFile();
   else
   {
   in >> strA;
   if (strA.left(4) == "_msg")
       out << msgInputOutputDialog();
   /*дальше аналогичные конструкции*/
   }
 
}
 

Функция, которая срабатывает, если strA.left(4) == "_bin"
Код
C++ (Qt)
QString MainWindow::setGetFile()
{
   QDataStream msger(&socket);
   FILE *files;
   int chr;
   i = 0; end = 0;
   strA = strA.mid(5);
   if (strA.mid(0, 3) == "get")
      k = 1;
   else if (strA.mid(0, 3) == "set")
         k = 2;
   strA = strA.mid(5);
   while ((ch = strA.mid(i, 1)) != "\"")
   {buf1+=ch;i++;}
   strA = strA.mid(i+3);
   i = 0;
   while((ch = strA.mid(i, 1)) != "\"")
   {buf2+=ch;i++;}
 
   if (k == 1) //это ветка, если клиент отправляет файл. ОНа работает и на нее можно не обращать внимания
   {
    files = fopen(buf1.toAscii(), "rb");
    msger << QString("Файл загружен на Ваш компьютер");
    msger << buf2;
    end = QFile(buf1).size();
    msger << end;
    while ((chr = getc(files))!= EOF)
       msger << chr;
    fclose(files);
   }
   else //Это ветка, если клиент принимает файл. С ней проблемы
   {
       msger >> end;
       if (end != 0){
       getFile();
        return QString("Файл скачан на компьютер");}
       else
          return QString("Невозможно записать файл на компьютер");
   }
   return QString("Готово");
}
 

Вот функция getFile() которая вызывается и по истинности условия в слоте и в setGetFile()
Код
C++ (Qt)
void MainWindow::getFile()
{
   static int h = 0; int ch = 0;
   static FILE *file1;
   if (h == 0) {
   file1 = fopen(buf2.toAscii(), "wb");
   h = 1;
   }
   QDataStream msger(&socket);
   msger >> ch;
    fileSize++;
   putc(ch, file1);
   if (fileSize == end)
   {
       fclose(file1);
       end = 0; fileSize = 0;
   }
}
 

Может быть еще есть какие предложения :)


Название: Re: Непонятная проблема с приемом данных int в QTcpSocket
Отправлено: ритт от Май 01, 2010, 19:05
фигня какая-то...
мб лучше для начала подучить теорию?


Название: Re: Непонятная проблема с приемом данных int в QTcpSocket
Отправлено: G-virus от Май 01, 2010, 21:17
фигня какая-то...
мб лучше для начала подучить теорию?

классно ты помог мне ваще))))))))))


Название: Re: Непонятная проблема с приемом данных int в QTcpSocket
Отправлено: ритт от Май 02, 2010, 02:33
фигня какая-то...
мб лучше для начала подучить теорию?

классно ты помог мне ваще))))))))))

ой, ладно, уел...
хорошо, я отложу на сейчас другие дела - накатаю специально для тебя и вместо тебя оптимальный рабочий код, затем, если ты в здравом уме и этот код тебе самому нужен, а не лишь "сдать и забыть", ты начнёшь ковыряться в этих сорцах, сталкиваться с (мало|не)знакомыми конструкциями и техниками (1) и задаваться вопросами, которые непременно сочтёшь необходимым задавать здесь же (2) - поначалу тебе будут отвечать по существу - объяснять то и это, что вызовет новые вопросы, на которые в итоге получишь ответ вида "читай книжки/гугли/учи матчасть"...

дык, я вот лучше сэкономлю нам обоим время и отвечу сразу (собственно, уже ответил ранее)...
ну, разве что, дополню ответ: если оно тебе самому надо - у кутэ замечательная документация и богатый набор экзамплов; если нет - заплати кому-нибудь чтобы сделали за тебя - в жизни всё-равно не пригодится.

-- приложение 1. аргументация:
1) * while ((chr = getc(files))!= EOF)
даже слов нет комментировать ЭТО! однако, побайтное чтение файла - хрен с ним, а побайтное ожидание по tcp - ...
* собственный чудо-протокол на основе строк? ну надо же! а ребята в гугле фигнёй страдают - выдумывают какие-то техники оптимизации данных, сохранения бинарного формата между версиями, компрессии на лету...во дурачьё

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

зы. задача на полчаса для средненького кодера

зыы. извиняюсь, конечно, за бестактность, но ответ был подсказан чуть ли не десять постов назад - > Посмотри кутешные примеры по QTcpSocket.


Название: Re: Непонятная проблема с приемом данных int в QTcpSocket
Отправлено: G-virus от Май 02, 2010, 11:35
Что и требовалось доказать. "Гугли, читай документацию/книжки, смотри примеры (в которых 90% ненужного говна)". Если тема настолько бесполезна, можно было и сказать мне об этом в пм, а тему удалить, и не флудить тут, что я такой тупой задаю вопросы на форуме, когда есть великий могучий ГУГЛ!  Причем тут чудо-протокол на основе строк? Я че говорил что изобрел б**ть какой-то протокол??? Если тебе не нравится что я принимаю побайтно по tcp, обязательно нужно выделываться, типо я такой нубло огорчил тебя, такого Гуру своим говнокодом? Может быть я не знаю, что в этом могут быть проблемы. И че? Я теперь враг народа? Или ты хочешь сказать, что родился с компьютером в зубах? Смысл тогда держать форум, если одни ответы: "Смотри примеры", "Гугли", "Читай книжги/ассистент/матчасть" и т.п.

Слов нет, ты конечно выручил меня и помог с "проблемой" ;D А я сижу, дурак, переделываю этот код, пытаюсь что-то сделать. Хотя всего-то стоило увидеть фразу: "ГУГЛИ!"


Название: Re: Непонятная проблема с приемом данных int в QTcpSocket
Отправлено: ритт от Май 02, 2010, 20:16
> Смысл тогда держать форум <snip>
да я вот тоже думаю об этом...смысл в стотысячный раз писать одно и то же, если вашему брату лень даже поиском по форуму воспользоваться?

> Если тебе не нравится что я принимаю побайтно по tcp, обязательно нужно выделываться <snip>
я не выделывался, я о???л :) будь адекватнее, ага? побайтное ожидание не может нравиться по определению да кому угодно...и это не моя прихоть.
вот и получается, что ты понятия не имеешь о том, как работать с сокетами. что же тогда обижаешься на резонное предложение подучить теорию?
ведь программист должен уметь не только читать чужие исходники, но и просто обязан писать собственные, а для этого зачастую необходимо читать километры спецификаций и манов и др., и пр.
так чего же ты дуешься? прям детский сад, чес-слово ))


Название: Re: Непонятная проблема с приемом данных int в QTcpSocket
Отправлено: G-virus от Май 02, 2010, 21:52
А я прям вот только вчера скачал QtCreator, скомпилил библу и пытаюсь что-то делать)))))))