Russian Qt Forum
Ноябрь 25, 2024, 05:24 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Непонятная проблема с приемом данных int в QTcpSocket  (Прочитано 10260 раз)
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. Если оставить месседжбокс, то все отлично принимается и записывается. Объясните пожалуйста, почему так, и можно ли как-то избавиться от зависимости от месседжбокса?
Записан
registrationfedser87
Гость
« Ответ #1 : Апрель 27, 2010, 07:36 »

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

Может быть на стороне клиента байты, пересылаемые сервером, успевают получаться(и вообще сервер уже успел отправить необходимые клиенту в данный момент байты)? Вызываешь ли ты flush у сервера? И вообще, по мне так подход к получению и отправке неверный. Посмотри кутешные примеры по QTcpSocket.

нет. flush-а нету. С месседжбоксом все правильно ведь работает, при чем тут flush Улыбающийся И почему не правильно?
« Последнее редактирование: Апрель 27, 2010, 15:51 от G-virus » Записан
registrationfedser87
Гость
« Ответ #3 : Апрель 27, 2010, 16:02 »

вызов TCPSocket.flush() на стороне сервера немедленно отправляет данные.
Почему мне кажется неправильно(может я и ошибаюсь конечно)-потому что передача идёт пакетами, и если ты скажем передаёшь 10 мегабайт это не значит что они у тебя придут одним пакетом. Т.е. тебе по кусочкам надо собирать необходимый пакет. Как пакет набран-тогда и обрабатываешь(т.е. ты допустим передаёшь сначала длину файла, и когда приходят куски пакетов ты их добавляешь в результирующий выходной файл пока не получишь все байты).
Записан
garryHotDog
Гость
« Ответ #4 : Апрель 27, 2010, 16:41 »

по flush() написано правильно....а еще есть такая штука как алгоритм "Нагла"
Записан
G-virus
Гость
« Ответ #5 : Апрель 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();
}
 
Записан
crossly
Гость
« Ответ #6 : Апрель 27, 2010, 18:09 »

данные пишутся по сигналу readyRead() ??
Записан
G-virus
Гость
« Ответ #7 : Апрель 27, 2010, 19:24 »

данные пишутся по сигналу readyRead() ??

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

fedser87
 Добавил flush(). Толку - 0. Только начинаются лаги, приходит лишняя информация на клиент, а результат один и тот же
« Последнее редактирование: Апрель 27, 2010, 19:29 от G-virus » Записан
registrationfedser87
Гость
« Ответ #8 : Апрель 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;
            }
        }
 
« Последнее редактирование: Апрель 28, 2010, 08:06 от fedser87 » Записан
crossly
Гость
« Ответ #9 : Апрель 28, 2010, 12:06 »

об этом я и говорю.... Улыбающийся
Записан
G-virus
Гость
« Ответ #10 : Апрель 28, 2010, 19:43 »

привожу кусок кода с примера:

То есть я должен прислать размер файла (что я в общем-то и делаю) а потом перед и после цикла приема файла поместить этот цикл, который Вы мне прислали так?
Записан
registrationfedser87
Гость
« Ответ #11 : Апрель 29, 2010, 07:40 »

Нет. Кусок я для примера привёл(хотел показать что надо ожидать получение необходимых байт). Ещё раз повторю, как писал crossly, тебе надо привязаться к сигналу readyRead() (чтобы не блокировать приложение в ожидании данных-это если у тебя неконсольное приложение), т.е. как приходит часть пакета, то срабатывает сигнал.
Алгоритм такой:
1. Получили размер файла и записали например в переменную fileSize, обнулили переменную currentFileSize (она будет показывать сколько байт мы получили);
2. Теперь каждый раз когда нам приходят байты, мы увеличиваем переменную currentFileSize на кол-во полученных байт(пусть скажем сейчас например получили X байт, мы увеличиваем currentFileSize+=X) и добавляем полученные байты в выходной файл и проверяем, достиг ли файл необходимого размера (точнее проверяем currentFileSize>=fileSize), если достиг,то заканчиваем приём файла.
« Последнее редактирование: Апрель 29, 2010, 07:52 от fedser87 » Записан
G-virus
Гость
« Ответ #12 : Апрель 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(), это поможет?

И по поводу сигнала. У меня просто на этот сигнал привязана функция, которая обрабатывает пришедшую строку и вызывает соответствующую функцию. Как не хотелось бы все приходящие данные пихать в файл Улыбающийся
« Последнее редактирование: Апрель 29, 2010, 16:01 от G-virus » Записан
G-virus
Гость
« Ответ #13 : Май 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;
   }
}
 

Может быть еще есть какие предложения Улыбающийся
Записан
ритт
Гость
« Ответ #14 : Май 01, 2010, 19:05 »

фигня какая-то...
мб лучше для начала подучить теорию?
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.22 секунд. Запросов: 21.