Название: [РЕШЕНО] Передать по сети большую структуру данных Отправлено: Vladimir от Ноябрь 24, 2014, 22:22 Есть некий список структур, который нужно передать с сервера на клиент, либо с клиента на сервер.
Сериализую список в QByteArray следующим образом: сначала добавляю заголовок в котором указываю, количество объектов в списке и размер передаваемых данных. Код: QByteArray arrBlockHead,arrBlockBody,arrBlockSend; на принимающей стороне сначала вычитываю заголовок: Код: headCommand headComm(-1); оттуда забираю тип присланных данных, размер sizeData и количество numbData и отдаю нужной функции на обработку: Код: void Client::procPacketSign(int sizeData, int numbData) Все вроде как работает до размера передаваемого списка ~2Kb, если передаваемых данных становится больше, то посылка начинает дробиться на меньшие части, в одной из которых будет заголовок с нужной инфой, во второй части естественно нет. Поэтому происходит неправильное чтение из сокета, ну и дальнейшая каша. Вопрос: как правильно реализовать такого рода обмен? Самому дробить на части, но как это правильно сделать и гарантирует ли TCP\IP ту последовательность прихода данных с которой они были записаны в сокет? Название: Re: Передать по сети большую структуру данных Отправлено: DenKor29 от Ноябрь 24, 2014, 22:37 Все вроде как работает до размера передаваемого списка ~2Kb, если передаваемых данных становится больше, то посылка начинает дробиться на меньшие части, в одной из которых будет заголовок с нужной инфой, во второй части естественно нет. Поэтому происходит неправильное чтение из сокета, ну и дальнейшая каша. Вопрос: как правильно реализовать такого рода обмен? Самому дробить на части, но как это правильно сделать и гарантирует ли TCP\IP ту последовательность прихода данных с которой они были записаны в сокет? TCP (IP идентификатор 6) — «гарантированный» транспортный механизм с предварительным установлением соединения, предоставляющий приложению надёжный поток данных, дающий уверенность в безошибочности получаемых данных, перезапрашивающий данные в случае потери и устраняющий дублирование данных. TCP позволяет регулировать нагрузку на сеть, а также уменьшать время ожидания данных при передаче на большие расстояния. Более того, TCP гарантирует, что полученные данные были отправлены точно в такой же последовательности. В этом его главное отличие от UDP. Правильно ваш случай реализовать через механизм комманд протокола 7 уровня. Например 1 команда - передача одной структуры (фиксированный заголовок формата пакета) + сам QByteArray. 2 команда подтверждение приема структуры. 3 команда - Инициализация соединения с обменом информацией о версиях протокола и фичах P.s. Сразу вспомнил как я програмировал kflip и binkf для сети фидонет ;D Название: Re: Передать по сети большую структуру данных Отправлено: DenKor29 от Ноябрь 24, 2014, 22:46 Соответсвенно работа идет через буфер ввода-вывода.
1. Считываете заголовок с фиксированным размером (размер буфера больше длины заголовка). 2. Выясняете размер передаваемых данных и считываете в буфер оставшиеся данные В текущей ситуацией с размером памяти можно считывать напрямую в QByteArray. Имхо прежде чем все реализовать продумайте логику комманд протокола. Название: Re: Передать по сети большую структуру данных Отправлено: Vladimir от Ноябрь 24, 2014, 23:09 Соответсвенно работа идет через буфер ввода-вывода. Как-то не совсем понятно..1. Считываете заголовок с фиксированным размером (размер буфера больше длины заголовка). 2. Выясняете размер передаваемых данных и считываете в буфер оставшиеся данные В текущей ситуацией с размером памяти можно считывать напрямую в QByteArray. Имхо прежде чем все реализовать продумайте логику комманд протокола. Через буфер ввода-вывода - это QDataStream?! Как-то с ним мало работал.. Всегда было проще фиксированную структуру записать в сокет, затем ее же и вычитать.. в чем преимущество в данном случае QDataStream, он не будет бить данные и все считает за раз? Название: Re: Передать по сети большую структуру данных Отправлено: DenKor29 от Ноябрь 24, 2014, 23:55 Соответсвенно работа идет через буфер ввода-вывода. Как-то не совсем понятно..1. Считываете заголовок с фиксированным размером (размер буфера больше длины заголовка). 2. Выясняете размер передаваемых данных и считываете в буфер оставшиеся данные В текущей ситуацией с размером памяти можно считывать напрямую в QByteArray. Имхо прежде чем все реализовать продумайте логику комманд протокола. Через буфер ввода-вывода - это QDataStream?! Как-то с ним мало работал.. Всегда было проще фиксированную структуру записать в сокет, затем ее же и вычитать.. в чем преимущество в данном случае QDataStream, он не будет бить данные и все считает за раз? Например вам нужно передать бинарные файлы неизвестной длины. Буфер ввода-вывода в данном случае это массив байт которые вы считываете, но пока не обрабатываете. Например ваш буфер - это массив байт (допустим 1Мб). По сигналу readyread() вы этот массив заполняете данными с начала массива. Точно известно (по вашей версии протокола), что первые 4 байта это размер файла. Затем идут данные файла. Окончание потока данных это размер следующего файла 0. Принцип работы протокола 1. Считывете из вашего буфера размер файла - 4байта. Если 0 то выходите. 2. Создаете новый QByteArray 3. Считываете данные из буфера в этот QByteArray 4. Данные из буфера удаляете (считанные) 5. Получете файл 6. Переходите к пункту 1 ========================================================= одной из которых будет заголовок с нужной инфой, во второй части естественно нет. Поэтому происходит неправильное чтение из сокета, ну и дальнейшая каша. =========================================================== Читайте данные через промежуточный буфер ввода-вывода. Все приходящие части нужно добавлять в единое целое. И только потом обрабатывать. В Вашем случае нужно начинать обработку только когда вы получаете весь массив данных. Пишите протокол передачи данных на бумаге . В вашем алгоритме не учитвается раздробление данных при передаче ;D Название: Re: Передать по сети большую структуру данных Отправлено: Vladimir от Ноябрь 25, 2014, 13:58 DenKor29, спасибо за разъяснения. Но получилось доделать свой вариант таким образом:
Код: while(sock.command->bytesAvailable()) Код: bool Client::waitRecvData(int sizeData) |