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

Бородатый физик

Новичок
  • Постов

    4
  • Зарегистрирован

  • Посещение

Репутация

0 Обычный
  1. для json есть весьма компактные реализации. собирайте-разбирайте строки от HTTP-сервера на лету, заодно выполняя их валидацию, иначе кто-нибудь додумается записать вам GET-запросом в параметр по смещению абракадабру, после чего будет весьма неприятно.
  2. Код, естественно, смотрел. Функционал, касающийся Linger, присутствует. Я имел ввиду скрытые баги, про которые, возможно, все знают, и только я один прощелкал...
  3. Здравствуйте, уважаемые форумчане! Некоторое время назад передо мной была поставлена задача – разработать 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
×
×
  • Создать...