Здравствуйте!
Подскажите пожалуйста, каким образом реализовать асинхронную запись в один и тот же открытый сокет из различных задач(нескольких)?
Возможно ли это в данной ОС?
Необходимо одновременно обрабатывать комманды пользователя, по (непредсказуемым)прерываниям отправлять
сообщение и закрывать сокет если нет активности n-секунд
Например запускается задача 1, в цикле которой вызываются функции: tcp_read(чтение из сокета), com_interpret(обработка пакета), tcp_write(отправка ответа).
Далее запускается задача 2: прикрепляется прерывание к мутексу mutex_attach_irq(вход внешнего прерывания), далее в бесконечном цикле ожидаем прерывания (mutex_wait) и отправляем информацию о прерывании в тот же сокет через tcp_write.
Запуск задачи-монитора для закрытия соединения по таймауту.
Код:
void tcp_task1 (){
lsock = tcp_listen (&ip, 0, serv_port);
for (;;) {
user_socket = tcp_accept (lsock);
for (;;) {
tcp_read (user_socket,...);
com_interpret(...);
tcp_write (user_socket,...);
}
}
close:
......
}
void tcp_task1 (void *data){
mutex_attach_irq(&ext_lock, EXT_IRQ_DEF, (handler_t)ext0_handler, 0);
for (;;) {
mutex_wait (&ext_lock);
if(user_socket){
tcp_write (user_socket,...);
}
}
close:
......
}
void tcp_act_mon (void){
for (;;) {
if (user_socket)){
if (tcp_inactivity (user_socket) > n) {
tcp_close(user_socket);
}
}
timer_delay (&timer, 1000);
}
}
Каким образом определить активность, защищать от одновременного доступа, закрывать, записывать и освобождать память сокета?
Существуют рабочие решения?
Перепробовал массу вариантов с мутексами и сигналами. Система постоянно падает (попытка освободить уже свобожную память сокета и магические чиста пула памяти не те), либо выводит асерты(в основном о доступе к закрытому соединению).
Так же интересует вопрос работы с несколькими соединениями.
Аналогично примеру telnetd, но так же с асинхронной отправкой пакетов из разных задач.
Код:
void task_server (void *data){ // задача слушает порт и при подключении создает задачу для приема пакетов
lsock = tcp_listen (&ip, 0, serv_port);
for (;;) {
sock = tcp_accept (lsock);
task_create (task_tcp_request, &tcp_slots[n], "task_tcp_request", 60, tcp_slots[n].stack_task_req, 1000);
}
}
void task_tcp_answer (void *arg){ //задача для отсылки сообщений
for (;;) {
slot_msg = (slots_t *) mutex_wait (&lock_answer); // можно сигналить из любой задачи?
tcp_write (slot_msg->sock, slot_msg->str_val, slot_msg->int_val);
}
}
void task_tcp_request (void *arg)
{
slots_t *slot_msg = (slots_t*) arg;
for (;;) {
n = tcp_read (slot_msg->sock, buff, 200); // получаем данные
com_interpret(...); // обрабатываем, может запустить отдельную задачу, которая через время выдаст
//результат для отправки через mutex_signal (&lock_answer...);
mutex_signal (&lock_answer, slot_msg); // шлем сигнал задаче task_tcp_answer для отправке ответа
}
closed_req:
...
...
...
task_exit (0);
}
void task_tcp_act_mon (void *arg) { // отслеживание неактивных соединений
...
for (;;) {
for (n=0; n<MAXSESS; n++){
if (tcp_inactivity (tcp_slots[n].sock) > eth_timeout) { // перебираем все сокеты и закрываем если таймаут
tcp_close (tcp_slots[n].sock);
}
}
timer_delay(&timer, 1000);
}
}
В примере выше имеется задача-отправитель (task_tcp_answer), которая ждет сигнала мутека.
В качестве сообщения передается указатель на структуру, содержащую указатели на сокет, буфер с данными и размер буфера для передачи.
Задачи (task_tcp_request) просто принимают данные, отдают интерпретатору команд, который сигналит мутексом со структурой описанной выше.
Задача монитор перебирает все сокеты и закрывает с истекшим временем ожидания.
Этот пример рабочий. Но иногда наблюдаются аномалии - не все сигналы мутексов отрабатываются, при интенсивной работе подтормаживает. Хитрой комбинацией открытия и закрытия соединения может упасть все - было один раз за тысячу тестов.
Пример с телнетом несовсем подходит, так как нужно параллельно принимать комманды из сокета, запускать задачи вычисления и выдавать в сокет результат асинхронно.
Реализовывал кто-нибудь подобное?