Бородатый физик
-
Постов
4 -
Зарегистрирован
-
Посещение
Сообщения, опубликованные Бородатый физик
-
-
-
Опубликовано · Изменено пользователем Бородатый физик · Пожаловаться
Да запросто может такое быть. Что же Вы в код lwip не заглядывали чтоли?Код, естественно, смотрел. Функционал, касающийся Linger, присутствует. Я имел ввиду скрытые баги, про которые, возможно, все знают, и только я один прощелкал...
-
Здравствуйте, уважаемые форумчане!
Некоторое время назад передо мной была поставлена задача – разработать 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. Целиком выкладывать не стал, т.к. там можно заблудиться...
Заранее спасибо.
Изменение настроек через http/ajax
в Программирование
Опубликовано · Пожаловаться
для json есть весьма компактные реализации.
собирайте-разбирайте строки от HTTP-сервера на лету, заодно выполняя их валидацию, иначе кто-нибудь додумается записать вам GET-запросом в параметр по смещению абракадабру, после чего будет весьма неприятно.