Jump to content

    
Sign in to follow this  
mantech

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

Recommended Posts

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

Решил сделать на данном стеке несколько соединений,  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

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this