Jump to content

    
Sign in to follow this  
IvanPletnev

LWIP Socket API блокировка задачи

Recommended Posts

Доброго времени суток, уважаемые коллеги! Встала задача принимать пакеты из UART и передавать их в сеть. Запустил задачу-сервер на Socket API из примера ST, проверил, send - receive работает. Но когда дело дошло до реальной реализации, выяснилось, что функции accept и receive намертво блокируют задачу. Блокировку функцией accept решил вот такой нехитрой конструкцией:

    	if (accept_state==0){
    		newconn = accept(sock, (struct sockaddr *)&remotehost, (socklen_t *)&size);//принимаем входящее подключение
    		accept_state=1;
    	}

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

 

 while (1)
    {
    	if (accept_state==0){
    		newconn = accept(sock, (struct sockaddr *)&remotehost, (socklen_t *)&size);//принимаем входящее подключение
    		accept_state=1;
    	}
        event=osMessageGet(UART_RX_QHandle,10);//получаем указатель на структуру, которую нужно передать в сокет
        if (event.status==osEventMessage){
        	printf ("Queue received at %lu\r\n", osKernelSysTick());
        	pDataToSend=(UART_RX_Data*)event.value.v;
        	HAL_GPIO_TogglePin(LD2_GPIO_Port,LD2_Pin);
        	send(newconn, pDataToSend->payload, pDataToSend->size, 0);//отправляем данные в сокет
        	HAL_UART_Receive_IT(&huart3,uartRXBuffer,UART3RX_BUF_SIZE);//включаем приём в UART
        	printf ("Switch context at %lu\r\n", osKernelSysTick());
        	osThreadYield();
        }
    }

в общем, циклично, по приходу пакета в UART, в задачу-сервер через очередь передается указатель на данные, которые нужно отправить в сокет.

Вот теперь возникли два вопроса. Первый - как корректно завершить соединение по запросу от клиента? Попробовал сделать так:

        nbytes=recv(newconn, rxBuf, BUFLEN, MSG_PEEK);
        if (nbytes<=0){
        	close(newconn);
        }

Сразу перестала работать очередь, потому что функция recv наглухо блокирует задачу. Что подскажете?

И второй вопрос. Как отслеживать физический дисконнект? Может, кто уже решал эту задачу?

Share this post


Link to post
Share on other sites

На одном из форумов нашёл решение. После успешного accept создаётся задача, которой в качестве аргумента передаётся идентификатор сокета. И уже в этой задаче обрабатывается функция recv. Еще не пробовал, но, думаю, должно получиться.

Share this post


Link to post
Share on other sites
On 11/8/2019 at 6:07 PM, IvanPletnev said:

Доброго времени суток, уважаемые коллеги! Встала задача принимать пакеты из UART и передавать их в сеть. Запустил задачу-сервер на Socket API из примера ST, проверил, send - receive работает. Но когда дело дошло до реальной реализации, выяснилось, что функции accept и receive намертво блокируют задачу. Блокировку функцией accept решил вот такой нехитрой конструкцией:

И второй вопрос. Как отслеживать физический дисконнект? Может, кто уже решал эту задачу?

Добрый день!

Если использование TCP не обязательно, то на UDP неблокирующий приём сделать относительно легко.

Физический дисконнект отслеживается через состояние PHY. Можно использовать прерывание (смотрите описание регистров Вашей микросхемы физического

уровня).

 

Quote

На одном из форумов нашёл решение. После успешного accept создаётся задача, которой в качестве аргумента передаётся идентификатор сокета. И уже в этой задаче обрабатывается функция recv. Еще не пробовал, но, думаю, должно получиться.

Ресурсы памяти быстро закончатся при таком подходе.

Share this post


Link to post
Share on other sites

Возможно, что-то не так с платформенно-зависимыми настройками, завязанными на многопоточность, мьютексы, почтовые ящики? Состояние портов получал MIIшными запросами к "физике" коммутатора, проблемы были только в результате ошибок в самодельном переключателе контекстов и при слишком частом их переключении (около 100000 раз в секунду). А так HTTP, DNS, DHCP, Telnet, NetConsole нормально работали. Делал по примерами из документации к lwIP.

Share this post


Link to post
Share on other sites
В 08.11.2019 в 17:07, IvanPletnev сказал:

И второй вопрос. Как отслеживать физический дисконнект? Может, кто уже решал эту задачу?

А что такое "физический дисконнект" по Вашему?

Share this post


Link to post
Share on other sites
On 11/9/2019 at 6:29 PM, IvanPletnev said:

На одном из форумов нашёл решение. После успешного accept создаётся задача, которой в качестве аргумента передаётся идентификатор сокета. И уже в этой задаче обрабатывается функция recv. Еще не пробовал, но, думаю, должно получиться.

Попробовал сделать так, через создание новых задач, работает отлично! Если от клиента мы получаем запрос на закрытие соединения (FIN), в задаче, в которой крутится функция recv, корректно закрываем сокет, удаляем созданные задачи.

newconn = accept(sock, (struct sockaddr *)&remotehost, (socklen_t *)&size);//принимаем входящее подключение
    	if ((newconn>1)||(newconn<1)){
    		close(newconn);
    	}
    	else
    		if (newconn==1){
    			HAL_GPIO_WritePin(LD1_GPIO_Port,LD1_Pin, GPIO_PIN_SET);
    			socketReceiveTaskHandle=sys_thread_new("sockRecvTask",socketReceiveTask,(void*)newconn,256,osPriorityNormal);
    			socketSendTaskHandle=sys_thread_new("sockSendTask",socketSendTask,(void*)newconn,256,osPriorityNormal);
    		}

Еще нужно сделать, чтобы по прерыванию от PHY, сигнализирующему о какой-либо ошибке соединения, делалось тоже самое. 

 Надо тестировать, конечно.

On 11/11/2019 at 3:10 PM, ksv198 said:

Ресурсы памяти быстро закончатся при таком подходе.

Нет, в моём случае количество соединений ограничено, мне не нужно создавать много.

Share this post


Link to post
Share on other sites
1 час назад, IvanPletnev сказал:

Нет, в моём случае количество соединений ограничено,

А интернет, в который выставят ваше устройство голым разъемом, об этом знает? И главное, знают ли об этом русские хакеры (tm)?

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