You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

55 lines
6.1 KiB

etcp - extended transmission control protocol
Протокол для передачи-приёма, пободный TCP, реализованый отдельным модулем (etcp.c/h).
Задача протокола:
- передать пакеты через UDP (учитывая его особенности - потери, негарантированный порядок), восстанавливая порядок и потери.
- пакеты уже предварительно подогнаны под размер чтобы вмещались доп. заголовки и служебные фреймы.
-
На приёмной стороне создаются две очереди.
первая - сортированный linked-list - в нее добавляются принятые пакеты, но отсеиваются дубликаты и вставляются в нужное место.
и перемещаются в выходную очередь когда все нужные пакеты дошли.
при получении принятого пакета он сразу парсится, для всех hdr!=0 вызываем static upd_metric_for_transmitter(epkt*, buf*, size) - и он разгребает метрики, обновляя:
- rtt_last (roud-trip delay) для последнего пакета
- rtt average last 10
- rtt average last 100
- jitter как усредненное: jitter+=(abs(rtt_last_10-rtt_last)-jitter)*0.1f
- для retransmission request - если timestamp последней попытки передачи этого пакета больше rtt_last_10*1.2+jitter*2 то отправляем сейчас
при отправке также ограничиваем полосу пропускания: суммируем сколько байт отправлено всего (uint32_t), обновляем timestamp и расчетное число байт которое может быть отправлено на момент этого timestamp. и формируем таймер для отправки следующего пакета.
вторая - ll_queue - выходная осчередь с пакетами в строгом порядке (строгий инкремент по id).
struct epkt* = etcp_init() - инициализирует новый instance и выделяет под него память
etcp_free(struct epkt*)
etcp_rx_input(struct epkt*,uint8_t* pkt, uint16_t len) - принятый пакет на обработку
rx_output - через механизм ll_queue, функция не нужна.
новый пакет на передачу отправляется в очередь передачи ll_queue. используй callback для обработки очереди.
для передачи сформированных пакетов по udp:
etcp_set_callback(epkt*, &cbk) -> etcp_tx_output(struct epkt*,uint8_t* pkt, uint16_t len) - callback в управляющей структуре (отправка пакета в udp сокет)
внутренняя структура передачи:
при готовности отправить очередной пакет из очереди ll_queue пакеты перемещаются в linked_list (как отправленные но неподтвержденные), и освобождаются при получении подтверждения (ack).
int etcp_tx_queue_size(epkt*) - должна быть функция которая возвращает общее кол-во пакетов на передачу в очередях (входящей и рабочей)
Формат udp пакета:
<id> <timestamp> [<hdr> metrics] <hdr=0> <payload>
id - uint16_t циклический порядковый номер пакета (при передаче следующего пакета инкрементируется). при ретрансмиссии передается с этим же id и payload, но с обновленными остальными полями
timestamp - uint16_t текущий timestamp (циклическое, 16 бит, timebase = 0.1mS)
hdr - 1 байт:
payload - передаваемые полезные данные
metrics - опциональное поле для передачи служебных фреймов (ack, retransmission request, statistic reply)
hdr:
0x00 - hdr для payload (от следующего байта до конца пакета)
0x01 - hdr для отчета о timestamp (время приёма) принятого пакета, 4 байта: <id> <timestamp> - передаётся при очередной передаче пакета, для формирования статичтики на приёмной стороне. отчеты передаются для всех новых принятых пакетов с момента последней передачи. т.е. накапливаем timestamp-ы и передаём их. если пакет потерялся - не страшно.
0x10-0x2f - hdr для перезапроса пакетов (передачу каких пакетов надо повторить. значение определяет количество записей (номеров пакетов) от 1 до 32, если больше - 32 самых старых), далее по 2 байта идут ID пакетов. и в конце - 2 байта номер последнего пакета который ушел в выходную очередь (т.е. последний номер для успешно собранной цепочки)
если что-то еще надо можно добавить.
Если данных нет (очередь на передачу пустая) и нужно передать только метрику, то передаётся пакет с id=0 и без <hdr=0> <payload>. на приёмной стороне он определяется по отсутствию записи с hdr=0