Перейти к содержанию
    

Проблемы с lwIP стеком

Здравствуйте, уважаемые форумчане!

Некоторое время назад передо мной была поставлена задача – разработать GPS/ГЛОНАСС трекер с поддержкой специфичного протокола обмена данными поверх TCP (данный протокол уже реализован на удаленном узле на Linux, а я просто должен под него подстроиться). Основные настройки устройства должны осуществляться по USB (mass storage device + внутренняя flash-память МК + fatfs). Программа должна крутиться под управлением freeRTOS + lwip. В качестве МК был выбран st32f407vg (ф.STMicroelectronics).

 

Программа на данный момент рабочая, но осталось несколько нерешенных вопросов связанных с lwip стеком и, возможно, сетевым программированием. С чем, собственно, и прошу помочь. Заранее оговорюсь, с сетевым программированием столкнулся впервые в данном проекте. По ходу написания программы читал Стивенса (не от корки до корки, но общую суть, надеюсь, уловил).

 

Это было краткое введение, теперь суть проблемы. Работаю с блокирующими BSD сокетами. По протоколу на моем устройстве поднят сервер и клиент. Когда приходит на сервер FIN от удаленного узла, я закрываю и сервер, и клиента. Затем снова открываю. Клиент довольно быстро выполняет connect и начинает передавать данные. С сервером дела обстоят иначе. Ниже представлен кусок кода, как я поднимаю сервер (код целиком я прикреплю в конце поста).

 

recv_serverfd = socket(AF_INET, SOCK_STREAM, 0);
if (recv_serverfd < 0) {Error_Handler();}
                    
memset(&recv_IpAddr, 0, sizeof(recv_IpAddr));
recv_IpAddr.sin_family = AF_INET;
recv_IpAddr.sin_port = htons(rs_port);
recv_IpAddr.sin_addr.s_addr = htonl(INADDR_ANY);
                    
len = sizeof(lingr);
                    
if (setsockopt(recv_serverfd, SOL_SOCKET, SO_LINGER, (void*)(&lingr), len) != 0)
{
    #ifdef    UART_PRINTF
        printf("Setsockopt(recv_serverfd) error\r\n");
    #endif    //UART_PRINTF
}
                    
do
{
    status = bind(recv_serverfd, (struct sockaddr*)&recv_IpAddr, sizeof(recv_IpAddr));
}
while (status < 0);
                    
listen(recv_serverfd, 1);

 

Функция bind в цикле раз за разом возвращает -1. И длиться это может по разному: от милисекунд до минут. Для меня последнее критично, т.к. слишком долго восстанавливается связь. Тут Вы скажете, что это нормально. Что сервер переоткрывается на том же порте, и bind будет висеть до тех пор пока закрытое соединение не передаст все данные из передающего буфера. Но есть одно «НО» - сервер у меня принимает данные, но не передает. Тогда откуда задержка? Это первый вопрос.

 

Логичным продолжением стало использование параметра SO_LINGER. Как написано у Стивенса, данный параметр позволяет изменить поведение функции close. По умолчанию функция close возвращает управление немедленно, но если в передающем буфере остались данные, система попытается доставить данные собеседнику (l_onoff = 0, l_linger = 0). Это как раз рассмотренный выше случай.

 

Я пробовал изменить параметр на l_onoff = 1, l_linger = 0. Т.е. соединение должно отправить сегмент RST и перейти в состояние CLOSED, минуя состояние TIME_WAIT. В итого, когда я закрываю сокет, то получаю либо зависание при освобождении памяти в ф-ии close, либо HardFault.

При изменении параметра на l_onoff = 1, l_linger = 1. Результат такой же, как и во втором случае.

Отсюда вопрос №2: может быть параметр SO_LINGER не работает должным образом в lwip? Или я что-то неправильно понимаю.

 

Ну и, наконец, подошли к третьему вопросу. После всех мытарств, решил закрывать не серверный сокет, а присоединенный сокет. И наткнулся на очередные грабли – функция accept вызывается ровно столько раз, сколько указано в параметре backlog функции listen. Т.е. если я пишу “listen(recv_serverfd, 5);”, то функция accept отрабатывает ровно 5 раз и потом зависает на веки вечные. У меня складывается впечатление, что когда я закрываю присоединенный сокет, функция close не освобождает память, и стек считает, что у меня дескриптор занят. Почему так происходит? Может быть кто-то сталкивался с подобным поведением и сможет пнуть меня в нужном направлении?

 

Я прикрепил файл, в котором представлен урезанный код процедуры EthernetTask. Целиком выкладывать не стал, т.к. там можно заблудиться...

Заранее спасибо.

Ethernet_task.txt

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Отсюда вопрос №2: может быть параметр SO_LINGER не работает должным образом в lwip?
Да запросто может такое быть. Что же Вы в код lwip не заглядывали чтоли?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Да запросто может такое быть. Что же Вы в код lwip не заглядывали чтоли?

Код, естественно, смотрел. Функционал, касающийся Linger, присутствует. Я имел ввиду скрытые баги, про которые, возможно, все знают, и только я один прощелкал...

Изменено пользователем Бородатый физик

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я имел ввиду скрытые баги, про которые, возможно, все знают, и только я один прощелкал...

Там есть честный багтрекер. Ознакомьтесь.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Там есть честный багтрекер. Ознакомьтесь.

 

Спасибо за ссылку.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...