Всем доброго дня. Столкнулся с задачей, которую ранее не решал. Решил проконсультироватся с сообществом чтобы не изобрести очередной велосипед
Дано: необходимо переслать с клиента на сервер большой обьем данных (не хотелось бы ограничивать себя), с получением от сервера обратно подтверждения о получении данных.
Что есть. Есть ICS библиотека асинхронных сокетов, у которых есть send и recv (упрощенно).
вот я немного и подвис на этом. То есть соединение есть, данные туда сюда ходят, но как большие обьемы собрать в кучу, при этом учесть что может клиент отвалится и не полностью доставить данные, или они могут физически испортится (а значит надо хоть минимальный контроль с помощью CRC). Как потом, после сборки данных ответить клиенту что все ок. Иил через какое время у него данные повторно запросить. А таких клиентов может быть несколько, и по каждому надо накапливать буфер принимаемых данных.
В общем пока больше вопросов чем ответов. Может быть кто-то сможет базово что либо рассказать, или посоветовать как сформировать вопрос гуглю?
Здравствуйте, Alexey Voytsehovich, Вы писали:
AV>вот я немного и подвис на этом. То есть соединение есть, данные туда сюда ходят, но как большие обьемы собрать в кучу, при этом учесть что может клиент отвалится и не полностью доставить данные, или они могут физически испортится (а значит надо хоть минимальный контроль с помощью CRC). Как потом, после сборки данных ответить клиенту что все ок. Иил через какое время у него данные повторно запросить. А таких клиентов может быть несколько, и по каждому надо накапливать буфер принимаемых данных.
А ты для себя протокол обмена распиши:
1) Клиент шлет запрос на прием данных
2) Сервер отвечает
3) Клиент шлет кусок данных + CRC куска
4) Сервер подтверждает получение куска и совпадение контрольной суммы
5) Если все нормально — повторяем до победного конца, иначе уходим или на облом или на повтор передачи куска
Соответственно сервер куски данных до завершения должен ложить хотя бы в файловый поток...
WBR, Dmitry Beloshistov AKA [-=BDS=-]
Re[2]: Пересылка через сокеты больших обьемов данных
Здравствуйте, DarkMaster, Вы писали:
DM>Здравствуйте, Alexey Voytsehovich, Вы писали:
AV>>вот я немного и подвис на этом. То есть соединение есть, данные туда сюда ходят, но как большие обьемы собрать в кучу, при этом учесть что может клиент отвалится и не полностью доставить данные, или они могут физически испортится (а значит надо хоть минимальный контроль с помощью CRC). Как потом, после сборки данных ответить клиенту что все ок. Иил через какое время у него данные повторно запросить. А таких клиентов может быть несколько, и по каждому надо накапливать буфер принимаемых данных.
DM>А ты для себя протокол обмена распиши:
DM>Соответственно сервер куски данных до завершения должен ложить хотя бы в файловый поток...
дык вроде ж tcp-ip это делать умеет? или я где то чтото не так понял?
Здравствуйте, Alexey Voytsehovich, Вы писали:
AV>Всем доброго дня. Столкнулся с задачей, которую ранее не решал. Решил проконсультироватся с сообществом чтобы не изобрести очередной велосипед
AV>Дано: необходимо переслать с клиента на сервер большой обьем данных (не хотелось бы ограничивать себя), с получением от сервера обратно подтверждения о получении данных.
AV>Что есть. Есть ICS библиотека асинхронных сокетов, у которых есть send и recv (упрощенно).
AV>вот я немного и подвис на этом. То есть соединение есть, данные туда сюда ходят, но как большие обьемы собрать в кучу, при этом учесть что может клиент отвалится и не полностью доставить данные, или они могут физически испортится (а значит надо хоть минимальный контроль с помощью CRC). Как потом, после сборки данных ответить клиенту что все ок. Иил через какое время у него данные повторно запросить. А таких клиентов может быть несколько, и по каждому надо накапливать буфер принимаемых данных.
AV>В общем пока больше вопросов чем ответов. Может быть кто-то сможет базово что либо рассказать, или посоветовать как сформировать вопрос гуглю?
Делить большой кусок на чанки (chunk)
Например так:
1. Посылаем серверу пакет — сейчас будет кусок данных (размера DataSize, поделенный на чанки ChunkSize)
packed record
PacketType : Byte; // control packet type (start chunking, for example 1)
DataSize : LongWord;
ChunkSize : Word;
end;
Сервер, генерирует ChunkStreamID и отвечает
packed record
PacketType : Byte; // control packet type (confirm chunking 2)
ChunkStreamID: Word // возвращаем с сервера ChunkStreamID - уникальное для сервера число, по которому будет идентифицироваться кусок, который мы пересылаем.end;
2. Посылаем чанки
packed record
PacketType : Byte; // chunk packet type, 3
ChunkStreamID: // previously returned by server
ChunkNumber : LongWord // инкрементируем для каждого чанка
ChunkData: array [ChunkSize] of Byte;
end;
Последний чанк-пакет может быть меньше предыдущих (данных меньше)
Теперь придумываем спопобы синхронизации, опишу для TCP, CRC уже сам протокол проверит:
На сервере создаем запись — будет огромный кусок данных такого то размера и так то поделенный.
Собираем чанки в массив по ChunkStreamID и сортируем по ChunkNumber. Если какой то чанк для ChunkStreamID не пришел, например через 10 sec после последнего пакета по ChunkStreamID — пересылка обламалась. Можем про это проинформировать клиента:
packed record
PacketType : Byte; // control packet type, (chunking failed, 4)
ChunkStreamID: // previously returned by serverend;
Все пришло (DataSize <= ReceivedChunkCount * ChunkSize) — собираем бааальшой буфер. Нотифицируем клиента что все гут
packed record
PacketType : Byte; // control packet type, (chunking SUCCESS, 5)
ChunkStreamID: // previously returned by serverend;
Так как протокол ассинхронный, неплохо будет наставить таймаутов где надо. Не пришло то то за такое то время — делаем то то.
Надеюсь все понятно?
Re[2]: Пересылка через сокеты больших обьемов данных
Здравствуйте, Danchik, Вы писали:
D>Здравствуйте, Alexey Voytsehovich, Вы писали:
AV>>Всем доброго дня. Столкнулся с задачей, которую ранее не решал. Решил проконсультироватся с сообществом чтобы не изобрести очередной велосипед
D>Делить большой кусок на чанки (chunk) D>Например так:
D>Так как протокол ассинхронный, неплохо будет наставить таймаутов где надо. Не пришло то то за такое то время — делаем то то. D>Надеюсь все понятно?
ну вроде примерно так и я думал, вот только вот что меня напрягает — вроде бы как tcp-ip протокол тоже умеет чанковать и собирать на другой стороне? или же я заблуждаюсь и он это умеет делать в пределах 64К?
Я не умею быть злым, и не хочу быть добрым.
Re[3]: Пересылка через сокеты больших обьемов данных
Здравствуйте, Alexey Voytsehovich, Вы писали:
AV>Здравствуйте, Danchik, Вы писали:
D>>Здравствуйте, Alexey Voytsehovich, Вы писали:
AV>>>Всем доброго дня. Столкнулся с задачей, которую ранее не решал. Решил проконсультироватся с сообществом чтобы не изобрести очередной велосипед
D>>Делить большой кусок на чанки (chunk) D>>Например так:
D>>Так как протокол ассинхронный, неплохо будет наставить таймаутов где надо. Не пришло то то за такое то время — делаем то то. D>>Надеюсь все понятно?
AV>ну вроде примерно так и я думал, вот только вот что меня напрягает — вроде бы как tcp-ip протокол тоже умеет чанковать и собирать на другой стороне? или же я заблуждаюсь и он это умеет делать в пределах 64К?
Здравствуйте, Alexey Voytsehovich, Вы писали:
AV>Здравствуйте, Danchik, Вы писали:
D>>Здравствуйте, Alexey Voytsehovich, Вы писали:
AV>>>Всем доброго дня. Столкнулся с задачей, которую ранее не решал. Решил проконсультироватся с сообществом чтобы не изобрести очередной велосипед
D>>Делить большой кусок на чанки (chunk) D>>Например так:
D>>Так как протокол ассинхронный, неплохо будет наставить таймаутов где надо. Не пришло то то за такое то время — делаем то то. D>>Надеюсь все понятно?
AV>ну вроде примерно так и я думал, вот только вот что меня напрягает — вроде бы как tcp-ip протокол тоже умеет чанковать и собирать на другой стороне? или же я заблуждаюсь и он это умеет делать в пределах 64К?
В принципе, все можно возложить на TCP/IP, но если вы хотите слать асинхронно, то размер буфера действительно ограничен. В синхронном варианте — просто шлете первый кусок с размером:
packed record
PacketType : Byte; // sending buffer
DataSize: LongWord // размер данныхend;
И досылаете остальные данные простым send в цикле пока буфер не закончится.
Re[4]: Пересылка через сокеты больших обьемов данных
Здравствуйте, Alexey Voytsehovich, Вы писали:
AV>Дано: необходимо переслать с клиента на сервер большой обьем данных (не хотелось бы ограничивать себя), с получением от сервера обратно подтверждения о получении данных.
AV>Что есть. Есть ICS библиотека асинхронных сокетов, у которых есть send и recv (упрощенно).
Правильно, зачем изобретать велосипед, когда все уже изобретено до нас
Обратимся к мировой практике.
Допустим есть сайт, на нем есть гигабайтный файлик. Нужно его скачать.
Как обычно решают такую задачу? Точнее каковы способы ее решения?
1. Качать Ыксплорером
Обрыв связи — и перезакачивать все заново.
Это обычный TCP-стриминг.
2. Качать Оперой/Огнелисом.
При обрыве связи, есть возможность возобновления закачки.
Это более интеллектуальная передача контента, с возможностью его "дособирания" по кусочкам
3. Качать даунлоадменеджером.
Многопоточная закачка, сразу нескольких кусков контента.
Максимальная производительность — если пакет от одного чанка где-то и застрял, то освободившуюся нишу в ширине канале займет пакет из другого чанка.
Это более продвинутая разновидность второго способа.
Для обеспечения надежности нужно каким-то образом возобновлять коннект. Предположим что связь осуществляется по принципу как в HTTP — на каждый запрос, должен быть ответ.
У каждой пары Request&Response должен быть уникальный ID — для запроса и ответа. RequestID и ResponseID.
При обрыве связи инициирующая сторона должна переконнектится и:
1. Если она передавала данные, то она должна спросить у другой стороны сколько данных та получила(по ID), и возобновить передачу с места обрыва
2. Если принимала данные, то также само: переконнектится, сказать что мне нужны данные для такого-то запроса(ID), с такого-то места
На каждой стороне должен быть таймаут на время жизни запроса.
Например если клиент при заборе данных с сервера, оборвался, и не переконнектился в течении timeout, то буффер (кеш ответа) на сервере очищается.
Как-то где-то так,
а сейчас спать!
хронический недосып, это очень и очень плохо...