|
4226 / 1796 / 211
Регистрация: 24.11.2009
Сообщений: 27,562
|
|
Передача больших объемов информации по TCP06.03.2012, 10:49. Показов 17350. Ответов 34
Метки нет (Все метки)
Надо передавать больше данных, чем может весть отдельный пакет. Когда данных мало, то всё понятно, можно отправить объект целиком и указать его sizeof на клинте и на сервере. А если данных много? Если превышен максимальный размер пакета? Ведь тогда объект будет порезан на куски. Как правильно склеить его? И как идентифицировать конец? Можно ли полагаться на равенство счётчика значению sizeof? А если тип данных может меняться? Если надо отправлять объекты разных классов? Когда данных мало, я могу принять сначала префиксный код размером в 1 байт и по switch решить, что именно и какого типа принимать дальше. Но если объект окажется рарезан, то первый байт пакета может быть и из серидины самого объекта. Как быть в этом случае? Искуственно клеить все объекты, какие могут подлежать передаче, в композитный объект и передавать всегда его? Если некоторые большие объекты меняются чаще других, то без толку раздуется трафик: при равных частотах изменения можно хоть както съекономить, передавая только после того, как изменятся все, а при разных частотах придётся весь композит передавать при каждом изменении часто изменяемых объектов, при этом будут повторно передаваться и редко изменяемые. Как это делается?
0
|
|
| 06.03.2012, 10:49 | |
|
Ответы с готовыми решениями:
34
Передача больших файлов по TCP Передача информации по TCP/UDP, находясь за роутером
|
|
2924 / 1274 / 114
Регистрация: 27.05.2008
Сообщений: 3,465
|
|
| 06.03.2012, 11:40 | |
|
Стоп. Какой такой "пакет" в TCP ??? TCP - протокол потоковой передачи данных с гарантированной доставкой. Т.е. ты запихиваешь в TCP сокет поток байтов, а реализация протокола, нисколько не интересуясь семантикой этих байтов, либо гарантированно доставляет их в гарантированно той же самой последовательности на приемный конец, либо генерирует ошибку.
Понятие "пакета" лежит на более низком уровне - на уровне IP протокола. Но реализация TCP протокола сама "разрежет" большой блок данных на IP пакетики нужного размера на передающей стороне, и сама же, без твоего участия, "склеит" их в правильной последовательности на приемном конце. Т.е. если ты хочешь передавать по TCP соединению некий "объект", просто учти, что TCP ничего не знает ни о каких "объектах" - он тупо работает только с потоком байтов. Тебе необходимо разработать собственный прикладной протокол (и он будет работать поверх TCP) для передачи "объекта". Например, можно передавать: 1. сначала некий "идентификатор" типа объекта, 2. затем размер данных объекта (байтовой последовательности) в байтах, 3. затем собственно поток байтов - данные объекта, 4. ну и по желанию - например, контрольную сумму пп.1-3, например, CRC32 или любую другую. А на приемной стороне - складываешь все принятые байты в буфер и анализируешь. Как только принял все поля 1-4 - анализируешь принятое, и если CRC сошлась, "восстанавливаешь" объект по принятым данным; иначе, либо просто отбрасываешь все принятое как "мусор", либо сигналишь на передающую сторону о проблеме. Вуаля!
0
|
|
|
4226 / 1796 / 211
Регистрация: 24.11.2009
Сообщений: 27,562
|
||
| 06.03.2012, 11:43 [ТС] | ||
|
0
|
||
|
2924 / 1274 / 114
Регистрация: 27.05.2008
Сообщений: 3,465
|
|
| 06.03.2012, 11:45 | |
|
А что за событие "получены данные"?
0
|
|
|
4226 / 1796 / 211
Регистрация: 24.11.2009
Сообщений: 27,562
|
||
| 06.03.2012, 11:51 [ТС] | ||
|
0
|
||
|
|
|
| 06.03.2012, 12:05 | |
|
taras atavin, разбей свой блок данных на чати скажем по 2048 байт. Вконце каждого сообщения передавай сигнатуру смысловое содержание которой: Передавался пакет 10 из 256 пакетов. На серваке пакуй принятые пакеты в файл (если какой то пакет не дошёл в выходном файле 2048 его инфы зануляй, потом допишешь). Когда приёдёт последний пакет посмотри сколько пакетов потерялось и отправь на сервак запрос с просьбой допередавать по новой выбранные пакеты. Как по мне всё прозрачно и просто...
0
|
|
|
2924 / 1274 / 114
Регистрация: 27.05.2008
Сообщений: 3,465
|
|
| 06.03.2012, 12:15 | |
|
Ага. Вот теперь понимаю, что ты имеешь в виду.
Это не совсем так, но, в общем, близко.... А по событию "получены данные" ты, очевидно, вызываешь функцию recv(), так? Так вот: функция recv() в очередной вызов вернет столько данных, сколько было успешно принято из передаваемого потока, накопленных после предыдущего вызова recv(). Отнюдь не факт, что все эти данные передавались в одном пакете IP - их могло быть и много, т.к. TCP, не получив какой-то пакет в последовательности, просто перезапрашивает его, задерживая передачу функции recv() всех последующих пакетов. А затем, успешно получив, отдает функции recv() все чохом. Попросту говоря, функция recv() в каждый вызов возвращает очередной "кусок" непрерывного потока байтов, передаваемого по TCP соединению. Содержит ли этот "кусок" целый объект или нет - никаких гарантий нет. Именно поэтому все, принятое функцией recv(), необходимо складывать в буфер и анализировать. Вот пример: - пусть ты передаешь два объекта: ABCDEFGH 12345678 и совершенно честно скармливаешь их функции send() на передающем конце: send(ABCDEFGH); send(12345678); - на приемном конце, в зависимости от того, как нижележащий протокол IP "разрежет" все на кусочки (а если шибко не повезет - может, в каждом кусочке будет всего по 1 байту данных! накладные расходы на заголовки будут, конечно, огромными, но это возможно.....), последовательными вызовами recv() ты можешь получить такие куски (все складываешь в буфер!!! и анализируешь): ABCD - анализируем, фигня-с... E - анализируем... мало-с.... FGH12 - опаньки! Анализируем, поняли, что приняли полный блок: ABCDEFGH, выбираем его и обрабатываем. 12 остается в буфере!!! и продолжаем накапливать данные: 3 4 5 678 - опаньки! Поняли, что приняли еще один блок: 12345678 - извлекаем из буфера, обрабатываем. И так далее. Добавлено через 2 минуты PS: -=ЮрА=-, твое предложение совершенно грамотное. Фокус в том, что реализация TCP протокола делает именно это же самое "невидимо" для прикладного программиста :-)
0
|
|
|
2924 / 1274 / 114
Регистрация: 27.05.2008
Сообщений: 3,465
|
|
| 06.03.2012, 12:25 | |
|
PPS: кстати, в приведенном примере может получиться и так, что первый же вызов recv() вернет сразу оба объекта:
ABCDEFGH12345678 Не беда! Анализируем содержимое буфера, выбираем объект ABCDEFGH и обрабатываем; потом снова анализируем то, что осталось в буфере и понимаем, что у нас есть еще один полноценный объект - 12345678. Вуаля. Добавлено через 2 минуты villu: можно и так. Конкретная реализация прикладного протокола на усмотрение автора :-)
0
|
|
|
4226 / 1796 / 211
Регистрация: 24.11.2009
Сообщений: 27,562
|
||||
| 06.03.2012, 12:39 [ТС] | ||||
|
Добавлено через 2 минуты
0
|
||||
|
2924 / 1274 / 114
Регистрация: 27.05.2008
Сообщений: 3,465
|
|
| 06.03.2012, 12:53 | |
|
Хм, ну вот как все это сделать - тут вариантов можно нафантазировать много...... решать-то все равно тебе.
Вполне себе здравое предложение от villu: в самом начале передавай размер требуемого буфера, аллокируй его (лучше использовать vector<>, если ты пишешь на C++), потом заполняй данными и анализируй. Для следующего объекта - новый буфер, и т.д. Вот полезная ссылка по внутренним потрохам сетей: http://book.itep.ru/1/intro1.htm
0
|
|
|
|
|
| 06.03.2012, 13:20 | |
|
Перечитав топик и посты с упоминанем динамического выделения памяти хотел бы отметить:
Допустим у нас блок данных 20 Мб, в зависимости от скорости подключения он будет транслироваться от минуты до получаса. За указанное время легко могут возникнуть сбои при передаче и TCP скажет пакет не дошёл.(т.е. не дошли все 20 МбО_о) Мы умные и припаяли к алгоритму перезапуск задачи и снова будем пытаться передать те самые присславутые 20 Мб и ... бесконечный цикл. Теперь смотрим вариант с чтением и передачей блока 20 Мб пакетами по 2 кБ. Передавая 1024 пакета можем потерять скажем 10 %, потом перезапустив будем передавать уже 10 % от 20 Мб и так пока не передадим все данные. Странно что все форумчане не применут указать мне когда делаю огромный буфер в оперативной памяти и советуют бить на части, зато при передаче ТСР хотим передать всё сразу (а ведь ОЗУ понядёжней сетевого трафика). Без обид передавать сразу весь объём данных - это нерациональность высшего порядка...
0
|
|
| 06.03.2012, 13:40 | |
|
Все это разруливается на уровне прикладного протокола
1: 20 мег выделять не надо, надо просто класть полученные куски в файл. 2: перезапуск после сбоя опять же не проблема, надо просто сказать серверу сколько уже получено (либо позицию с которой следует начать передачу), чтоб он начал читать файл с нужной позиции. И это опять же укладывается в модель <размер>:<данные> И да. TCP гарантирует последовательность принятия байт в том виде, в котором они отправлены. Ситуации "середина выпала" быть не может; либо принял все, либо обломился совсем. Добавлено через 10 минут : Кстати тут под словом "Файл" и имею ввиду сериализованный блок, который может хранится и в файле ( который на диске ). чтоб разночтений не возникло..
0
|
|
|
|
|||||
| 06.03.2012, 14:10 | |||||
|
Если мы передаём 1000 пакетов по 2 кБ то некоторые дойдут некоторые недойдут, те что дошли записали в файл, те что нет - обнулили их место в файле под 2048 байт. Когда дошли все 1000-чу пакетов смотрим те что не дошли (это будут нолики в середине файла) - это выпаввшая серидинка, вот эти пакеты и попросим отправить нам снова. Далее у меня к тебе вопрос - заччем каждый раз заморачиваться над размером буфера отдельного пакета???Сделали буфер константный и знаем что либо дошло 2048 байт либо не дошло. Число 2048 байт совсем не случайно - в ряде источников есть сведения что это оптимальный размер буффера для файловой записи, т.е. собирать на HDD наш файлик будем с максимально быстрой скоростью (т.е данные дошли и максимально быстро их записали в собираемый файл) Таким образом с буфером 2048 байт будем тратить минимально возможное время время на простой при буферизации файлового i/o... Добавлено через 1 минуту
0
|
|||||
| 06.03.2012, 14:31 | ||||||
либо мы получили 20 мегабайт, либо мы получили из них только 10 и нам 10 надо еще дочитать; какие такие "нолики в середине файла"?
Ты же предлагаешь:
0
|
||||||
|
|
|||
| 06.03.2012, 15:19 | |||
|
Содержание файла (условно 1-цам отображена записанная информация 0 простая запись нулей по величине буфера, т.е для конкретного случая 1 байт) 111101011 Просим сервер повторно выслать пакеты 5 и 7, что тут сложного? Добавлено через 3 минуты
0
|
|||
|
|
||
| 06.03.2012, 15:29 | ||
|
Пытался когда нибудь распараллелить передачу либо закачку??? Добавлено через 3 минуты villu, мне хотелось закричать, но так как ты реально не понимаешь обяъясняю ещё раз Есть файл 20 Мб. Серваком в цикле читаю его буфером 2048 байт и передаю send-ом за раз эти байты - это мой пакет данных. Клиент ждёт от сервака пакет - если вышел таймаут считаем что эти 2048 байт пока потерялись, тогда продвигаемся в собираемом файле на позицию 2048 от той на которой были и снова ждём пакет + запомнили что предыдущий пакет не получен, понятно нет?Получается файл 20 Мб передаём как бы 1000 чей отдельных файло чтоли(может так сможешь понять о чём толкую) Добавлено через 3 минуты При желании можно аинхронно считать файл 20 Мб сразу в 1000-чу потоков (черезp thread-нити) и все эти 1000-чу нитей пихануть клиенту на его 1000-чу нитей. Что быстрее будет один поток на 20 Мб или 1000-ча на 2 кБ как думаешь???
0
|
||
| 06.03.2012, 15:32 | |
|
без разницы 1 поток или 10000.
Само по себе чтение из сокета -- операция дорогая. Особенно на винде, где вызов recv (или WSARecv) может пойти по цепочке из 3 или больше dll. Поэтому чем больше блок вычитывания -- тем лучше.
0
|
|
| 06.03.2012, 15:32 | |
|
Помогаю со студенческими работами здесь
20
QTcp передача больших объемов данних... Свой сервер для хранения больших объемов информации Какой массив использовать для хранения больших объёмов информации? Связь SpinButton и Frame для отображения больших объемов информации Передача больших объемов данных c помощью MSXML2.XMLHTTP Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |
|
Новые блоги и статьи
|
|||
|
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL3_image
8Observer8 10.02.2026
Содержание блога
Библиотека SDL3_image содержит инструменты для расширенной работы с изображениями. Пошагово создадим проект для загрузки изображения формата PNG с альфа-каналом (с прозрачным. . .
|
Установка Qt-версии Lazarus IDE в Debian Trixie Xfce
volvo 10.02.2026
В общем, достали меня глюки IDE Лазаруса, собранной с использованием набора виджетов Gtk2 (конкретно: если набирать текст в редакторе и вызвать подсказку через Ctrl+Space, то после закрытия окошка. . .
|
SDL3 для Web (WebAssembly): Работа со звуком через SDL3_mixer
8Observer8 08.02.2026
Содержание блога
Пошагово создадим проект для загрузки звукового файла и воспроизведения звука с помощью библиотеки SDL3_mixer. Звук будет воспроизводиться по клику мышки по холсту на Desktop и по. . .
|
SDL3 для Web (WebAssembly): Основы отладки веб-приложений на SDL3 по USB и Wi-Fi, запущенных в браузере мобильных устройств
8Observer8 07.02.2026
Содержание блога
Браузер Chrome имеет средства для отладки мобильных веб-приложений по USB. В этой пошаговой инструкции ограничимся работой с консолью. Вывод в консоль - это часть процесса. . .
|
|
SDL3 для Web (WebAssembly): Обработчик клика мыши в браузере ПК и касания экрана в браузере на мобильном устройстве
8Observer8 02.02.2026
Содержание блога
Для начала пошагово создадим рабочий пример для подготовки к экспериментам в браузере ПК и в браузере мобильного устройства. Потом напишем обработчик клика мыши и обработчик. . .
|
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
|
SDL3 для Web (WebAssembly): Вывод текста со шрифтом TTF с помощью SDL3_ttf
8Observer8 01.02.2026
Содержание блога
В этой пошаговой инструкции создадим с нуля веб-приложение, которое выводит текст в окне браузера. Запустим на Android на локальном сервере. Загрузим Release на бесплатный. . .
|
SDL3 для Web (WebAssembly): Сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога
Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
|