Jump to content

    

uip стек, работа с несколькими соединениями

Приветствую.

Решил сделать на данном стеке несколько соединений,  2 клентских соединения с различными серверами и одно серверное, т.е. удаленный клиент может заходить на мой "сервер".

Вопрос - как разделять эти соединения? В lwip это делалось с помощью PCB или передачи адреса в аргументе, здесь подобного нет, есть только упоминание на какой-то указатель appcall, но в примерах автор намудрил все это со своей "полуосью" protothread и разбираться в данной теме довольно утомительно. 

Может кто делал что-то подобное без всяких треадов и пр. буду рад, если поделитесь...

Share this post


Link to post
Share on other sites

Там разве не по адресам-портам в том числе исходящим пакеты определяются? И по уникальному номеру соединения TCP. насколько помню, без проблем делал несколько "серверов" - DHCP, DNS, httpd.

Share this post


Link to post
Share on other sites
2 часа назад, GeorgK сказал:

И по уникальному номеру соединения TCP.

Где он находится, не подскажете? Я так понимаю, когда делаю connect мне его нужно где-то получить и когда я пападаю в appcall снова его откуда-то взять и уже идентифицировать, из какого соединения пришел коллбэк, так?

Share this post


Link to post
Share on other sites
В 16.10.2019 в 10:04, mantech сказал:

Где он находится, не подскажете? Я так понимаю, когда делаю connect мне его нужно где-то получить и когда я пападаю в appcall снова его откуда-то взять и уже идентифицировать, из какого соединения пришел коллбэк, так?

Видимо никто не знает или не хочет рассказать, ну да ладно, тогда более конкретизирую вопрос.

Допустим создал я 3 соединения с помощью функции connect(). Получил 3 указателя на структуры соединений.

Теперь надо отправить данные в адрес второго соединения, но в функции uip_send есть только указатель на буфер данных и длина передаваемых данных. Как "объяснить" ей, что данные должны уйти по адресу, указанному при соединении номер 2, а не 1 или 3??

Может по-тупому выражаюсь - не спец в сетевых стеках.  Если это нельзя сделать в принципе, порекомендуйте простой стек без использования динамической памяти, где это можно сделать...

Share this post


Link to post
Share on other sites
49 minutes ago, mantech said:

. . . но в функции uip_send есть только указатель на буфер данных и длина передаваемых данных. Как "объяснить" ей, что данные должны уйти по адресу, указанному при соединении номер 2, а не 1 или 3?? . . . 

Посмотрите в заголовочных файлах API какие ф-ии есть вообще. Очень давно с этим работал, не помню, возможно найдется таже ф-ия  (тоже имя) но с другим (большим, или в виде структуры) набором аргументов, или какое-нибудь sendTo. Чем могу . . . :bb:

Share this post


Link to post
Share on other sites

Извиняюсь заранее, если это прописные истины.
 

Спойлер

 

В структурах uip_conn и uip_udp_conn (см. фрагмент файла uip.h), создаваемой для каждого соединения TCP и UDP
соответственно, есть поля, соответствующие номерам локального и удалённого портов соединения TCP, есть адрес IP
той стороны соединения.


/**
 * Представление в uIP соединения TCP.
 *
 * Структура uip_conn используется для идентификации соединения. Все поля,
 * кроме одного полагаются не изменяемыми приложением. Исключением является
 * поле appstate, назначение которого - хранить какие либо данные (например,
 * указатели на открытые файлы) приложения, связанные с этим соединением.
 * Тип этого поля должен быть определён в заголовочном файле "uipopt.h"
 */
struct uip_conn {
  uip_ipaddr_t ripaddr;  /**< Адрес IP удалённой стороны. */

  uint16_t lport;        /**< Локальный (левый) порт TCP ("сетевой" порядок байт). */
  uint16_t rport;        /**< Удалённый ("правый") порт TCP ("сетевой" порядок байт). */

  uint8_t rcv_nxt[4];    /**< Последовательный номер, ожидаемый на приём. */
  uint8_t snd_nxt[4];    /**< Последовательный номер, посланный нами. */
  uint16_t len;          /**< Размер уже посланных данных. */
  uint16_t mss;          /**< Текущий макс. размер сегмента для соединеия. */
  uint16_t initialmss;   /**< Начальный макс. размер сегмента для соединеия. */
  uint8_t sa;            /**< Переменная для вычисления таймаута. */
  uint8_t sv;            /**< Переменная для вычисления таймаута. */
  uint8_t rto;           /**< Таймаут повторной передачи. */
  uint8_t tcpstateflags; /**< Состояние и флаги TCP. */
  uint8_t timer;         /**< Таймер повторной передачи. */
  uint8_t nrtx;          /**< Количество повторных передач последнего переданного сегмента. */

  /** Состояние приложения. */
  uip_tcp_appstate_t appstate;
};


/**
 * Указатель на текущее соединение TCP.
 *
 * Указатель uip_conn может быть использован для доступа к
 * текущему соединению TCP.
 */

extern struct uip_conn *uip_conn;
#if UIP_TCP
/* Массив содержит все соединения uIP. */
extern struct uip_conn uip_conns[UIP_CONNS];
#endif

/**
 * \addtogroup uiparch
 * @{
 */

/**
 * Четырёхбайтовый массив для вычислений 32-х битного последовательного номера.
 */
extern uint8_t uip_acc32[4];
/** @} */

/**
 * Представление в uIP соединения UDP.
 */
struct uip_udp_conn {
  uip_ipaddr_t ripaddr;  /**< Адрес IP удалённой стороны. */
  uint16_t lport;        /**< Локальный (левый) порт TCP ("сетевой" порядок байт). */
  uint16_t rport;        /**< Удалённый ("правый") порт TCP ("сетевой" порядок байт). */
  uint8_t  ttl;          /**< Время жизни пакета (TTL) по умолчанию. */

  /** Состояние приложения. */
  uip_udp_appstate_t appstate;
};

/**
 * Текущее соединение UDP.
 */
extern struct uip_udp_conn *uip_udp_conn;
extern struct uip_udp_conn uip_udp_conns[UIP_UDP_CONNS];

struct uip_fallback_interface {
  void (*init)(void);
  void (*output)(void);
};

В файле uipopt.h определяются подпрограммы для обработки соединений TCP и UDP:


/**
 * \var #define UIP_APPCALL
 *
 * Имя прикладной функции, которую uIP должен использовать
 * при обработке событий TCP/IP.
 *
 */

#define UIP_APPCALL     uip_server_appcall

/**
 * \var #define UIP_UDP_APPCALL
 *
 * Имя прикладной функции, которую uIP должен использовать
 * при обработке событий UDP.
 *
 */

#define UIP_UDP_APPCALL uip_udp_server_appcall


Прикладные программы (клиенты и серверы) фильтруют события по номеру
локального или удалённого порта:


void
uip_server_appcall(void)
{
  switch (uip_conn->lport) {
    case UIP_HTONS(HTTP_PORT):
         httpd_appcall(uip_conn->appstate);
         break;
    default:
         /* Соединение на незарегистрированный порт */
         debug("uip_server_appcall: uip abort()\n");
         uip_abort();
         break;
  }
}

void
uip_udp_server_appcall(void)
{
  /* Вроде POLL по таймеру вызывается отдельно для каждого "соединения", так что должно работать */
#ifdef CONFIG_UIP_RESOLV
  if(uip_udp_conn->rport == UIP_HTONS(DNS_PORT)) {
    resolv_appcall();
    return;
  }
#endif
  if(uip_udp_conn->lport == UIP_HTONS(DNS_PORT)) {
    dns_appcall();
    return;
  }
  if(uip_udp_conn->lport == UIP_HTONS(DHCP_CLIENT_PORT)) {
    dhcpc_appcall();
    return;
  }
  if(uip_udp_conn->lport == UIP_HTONS(DHCP_SERVER_PORT)) {
    dhcps_appcall();
    return;
  }
  if(uip_udp_conn->lport == UIP_HTONS(NBNS_PORT)) {
    nbns_appcall();
    return;
  }
}

При необходимости дальнейшей индивидуальной работы с соединением используется поле (указатель или структура,
как оно было определено в uipopt.h) appstate. Заполняется начальными значениями это поле при установлении соединения.


 

 

Share this post


Link to post
Share on other sites
3 часа назад, GeorgK сказал:

При необходимости дальнейшей индивидуальной работы с соединением используется поле (указатель или структура,
как оно было определено в uipopt.h) appstate.

Это все я понял, в appstate задается главная коллбэк-функция, у меня вопрос в другом, как разделить какому соединению пришел "пинок" коллбэка, при условии, что соединений несколько, причем одновременно. Но тут есть кое-какое понимание, равно, как и по приему данных из удаленного хоста, а вот в передаче данных удаленному хосту - нет. Передача не ведется из коллбека, она должна вызываться из основной программы. Вот о б этом бы по-подробнее...

 

ЗЫ. Смотрю сейчас и удивляюсь, или я тупой или автор сего поделья... Походу он даже не предусматривал такого, что программа может сама запросить передачу пакета удаленному хосту без "разрешения" стека:

   This function is used to send out a single segment of TCP
 * data. Only applications that have been invoked by uIP for event
 * processing can send data.  

Т.е. из основной программы я не имею права вызвать эту функцию, только из коллбека. А теперь вопрос, как я попаду в этот коллбэк, если удаленная сторона не передает пакеты, а ждет их от меня? Видимо только через вызов poll, и только тогда вызовется передача пакета в удаленный хост, и это офигенно быстро (период 0.5 сек!). Никакой другой функции, которая из основной программы может "пнуть" стек вызвать коллбэк для передачи я не увидел. Если это так, то такой стек только в топку...

Edited by mantech

Share this post


Link to post
Share on other sites

Вы совершенно правы, когда мне захотелось реализовать в загрузчике сетевую консоль (telnet, netconsole), именно по этой же причине пришлось переходить на lwIP - следующее поколение uIP и прикручивать многопоточность.

Share this post


Link to post
Share on other sites
1 час назад, GeorgK сказал:

именно по этой же причине пришлось переходить на lwIP

Я согласен, но этот стек мне не понравился, там все завязано на динамической памяти - шаг вправо, шаг влево - вылетаем в неустранимую ошибку, а шагов там этих, с учетом нескольких протоколов, по нескольку штук сокетов клиента и сервера, непредсказуемости работы самой сети, всяких случайных и не случайных разрывов и повторных соединений, причем все это асинхронно - и попасть в эту ошибку запросто, да еще траблы с выделением одной и той же pcb на разные коннекты, да и рестартануть стек нет возможности, только перезагрузка....  Это для меня неприемлимо. 

Кстати, кто что скажет про микрочиповский стек? Дам тоже везде "динамика" или что-то по устойчивее?

Edited by mantech

Share this post


Link to post
Share on other sites
On 10/16/2019 at 7:07 AM, GeorgK said:

Там разве не по адресам-портам в том числе исходящим пакеты определяются?

Там какая-то наркомания с тем, куда в данный текущий момент указывает 

struct uip_udp_conn *uip_udp_conn;
 

То есть я понимаю, конечно, что всё для фронта, всё для побе... лишь бы в мелкий 8-битник влезло, но с современными объемами памяти лучше использовать какие-то другие стеки, которые не позволят так легко стрелять себе в ногу.

Share this post


Link to post
Share on other sites

Может и вовсе проще будет написать свой UDP-стек с минимально нужным функционалом?

UDP прост как два пальца. Нативная организация позволит упростить код и сделать его более предсказуемым.

ИМХО, оптимально именно так, нежели пользоваться стеком почти 20-летней давности, о котором уже мало кто помнит. А ныне пользующихся и то меньше.

Share this post


Link to post
Share on other sites
В 22.10.2019 в 21:35, Arlleex сказал:

Может и вовсе проще будет написать свой UDP-стек с минимально нужным функционалом?

UDP прост как два пальца.

1) Нужна работа именно с TCP.

2) Этим сейчас и занимаюсь (пишу свой стек, с использованием кусочков из uip, которые понимаю, как работают:biggrin: )

Share this post


Link to post
Share on other sites
15 minutes ago, mantech said:

1) Нужна работа именно с TCP.

2) Этим сейчас и занимаюсь (пишу свой стек, с использованием кусочков из uip, которые понимаю, как работают:biggrin: )

В наше время писать свой стек TCP, ну это надо вообще от безделья томиться. 
Что, реально больше нечем заняться?  
 

Share this post


Link to post
Share on other sites

Кстати, в lwIP есть свой менеджер памяти - самостоятельно раздаёт память из выделенной области. Или это именно он глючный? Я-то с проблемами со стороны стека не сталкивался, возможно, из-за слишком щадящих условий.

Share this post


Link to post
Share on other sites
40 минут назад, GeorgK сказал:

Кстати, в lwIP есть свой менеджер памяти - самостоятельно раздаёт память из выделенной области.

К менеджеру памяти вопросов нет, он работает. Просто в самом стеке все не так однозначно, писал выше, что есть ситуации, при которых по докам все сделано правильно, но стек падает, редко, но все-таки. Система должна работать стабильно 24\7 с несколькими разнородными соединениями и не падать, допускается, если происходит падение стека, то система должна его восстановить без перезагрузок и зависаний. 

 

2 часа назад, AlexandrY сказал:

В наше время писать свой стек TCP, ну это надо вообще от безделья томиться.

Я бы лучше от безделия потомился, но того, что удовлетворяет  требованиям выше, или того, чтоб пол-года не портировать, не нашел...

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now