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

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

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

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

  • Посещение

Сообщения, опубликованные Бородатый физик


  1. для json есть весьма компактные реализации.

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

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

    Код, естественно, смотрел. Функционал, касающийся 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

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