45 / 48 / 5
Регистрация: 24.06.2013
Сообщений: 677

Утечки при использовании порта завершения и соккетов

29.10.2015, 14:33. Показов 1152. Ответов 12
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте, уважаемые Гуру! Реализовываю сервер с использованием порта завершения. Всё работает, всё прекрасно. Одно меня смущает - невозможно удалить хэндл из порта, пока не произойдёт завершение считывания-записи. Т.е. если клиент просто отключается, то порт продолжит хранить данные об этом хендле. По крайней мере я так понял из сети. Есть 2 идеи. 1 - фиктивные сообщения по таймауту с типом операции "удалить", 2 - идея двойной буфферизации. Т.е. имеем 2 порта завершения, в один момент активен только один из них. Как только количество хендлов превышает некоторый предел, порты переключаются. Это я основываю на предположении, что CloseHandle сама очистит устаревшие элементы. Собственно вопрос - что посоветуете? Читал много разного, но не нашёл конкретного решения по утечкам. А в остальном должен признать, что порт завершения - реально крутая вещи ИМХО.
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
29.10.2015, 14:33
Ответы с готовыми решениями:

Утечки памяти при использовании ExpandableListView
Всем здравствуйте. Сразу оговорюсь, что проект выполняется на Xamarin.Android. Но т.к. сама платформа не должна существенно отличаться от...

Утечки памяти при использовании new/delete для двумерных массивов
Добрый день. Суть в том, что есть несколько функций, получающих на вход и возвращающих двумерные массивы. Реализация передачи массивов...

Определение и принцип работы порта завершения ввода и вывода
Что такое порт завершения ввода и вывода данных и как он работает ? Это просто пул прерываемых сокетов?

12
Ушел с форума
Эксперт С++
 Аватар для Убежденный
16481 / 7444 / 1187
Регистрация: 02.05.2013
Сообщений: 11,616
Записей в блоге: 1
29.10.2015, 14:53
Цитата Сообщение от Retyrn0 Посмотреть сообщение
Одно меня смущает - невозможно удалить хэндл из порта, пока не произойдёт завершение считывания-записи. Т.е. если клиент просто отключается, то порт продолжит хранить данные об этом хендле.
Нет, не так. Клиент отключается - операция на сокете завершается - в
порт приходит сообщение. Далее его может обработать один из потоков пула.

Цитата Сообщение от Retyrn0 Посмотреть сообщение
Собственно вопрос - что посоветуете? Читал много разного, но не нашёл конкретного решения по утечкам
Нет там утечек. Когда вы заканчиваете работать с соединением, то хэндл
сокета должен быть закрыт. Начиная с этого момента порт больше не
использует данный хэндл. Все.

Цитата Сообщение от Retyrn0 Посмотреть сообщение
А в остальном должен признать, что порт завершения - реально крутая вещи
Это да. Хотя написать качественный сервер на портах завершения - задача не из простых.
1
45 / 48 / 5
Регистрация: 24.06.2013
Сообщений: 677
29.10.2015, 15:46  [ТС]
Цитата Сообщение от Убежденный Посмотреть сообщение
Нет там утечек. Когда вы заканчиваете работать с соединением, то хэндл
сокета должен быть закрыт. Начиная с этого момента порт больше не
использует данный хэндл. Все.
Звучит обнадёживающе, но мой сервер при событии отключения выводит сколько активных соединений. Я открываю, скажем, 5 вкладок. Потом все закрываю. Потом открываю новую - сервер выдаёт, что у меня 6 активных подключений. Если Вы имеете ввиду, что из порта удаляется сам хендл закрывшегося соккета, то есть возможность это обработать? Я ведь выделяю под каждый память для "данных завершения". Если утечек в порте не будет, то утечки будут в моей программе. Каким образом освобождать ресурсы?

Добавлено через 2 минуты
Простите, не прочитал...
Цитата Сообщение от Убежденный Посмотреть сообщение
Клиент отключается - операция на сокете завершается - в
порт приходит сообщение.
Т.е. если я навесил ожидание завершения считывания, то просто в обработчике определить закрыт ли соккет и если закрыт, освободить ресурсы? Правильно я понял?
0
Ушел с форума
Эксперт С++
 Аватар для Убежденный
16481 / 7444 / 1187
Регистрация: 02.05.2013
Сообщений: 11,616
Записей в блоге: 1
29.10.2015, 15:47
Я вижу здесь две совершенно разные проблемы:

1. отключение клиента (возможно, аварийное).

2. отсоединение сокетного хэндла от порта завершения.

Какую вы пытаетесь решить ?
0
45 / 48 / 5
Регистрация: 24.06.2013
Сообщений: 677
29.10.2015, 15:53  [ТС]
И могу ли я быть уверен, что операция завершения произойдёт всегда?

Добавлено через 1 минуту
Цитата Сообщение от Убежденный Посмотреть сообщение
Какую вы пытаетесь решить ?
Обе. Сервер будет работать постоянно и если при одном из двух вариантов произойдёт даже малейшая утечка, то со временем может получиться очень не приятно.

Добавлено через 3 минуты
Веб-соккетные подключения - необходимо KEEPALIVED - нужно всё держать. Но важно, чтобы при любом варианте отключения клиента сервер освобождал ресурсы. Текущая задача - 1 из Ваших предположенных -
Цитата Сообщение от Убежденный Посмотреть сообщение
1. отключение клиента (возможно, аварийное).
Добавлено через 1 минуту
Есть конечно вариант вытесняющего пула памяти для данных завершения, но если есть возможность решить вопрос иначе...
0
Ушел с форума
Эксперт С++
 Аватар для Убежденный
16481 / 7444 / 1187
Регистрация: 02.05.2013
Сообщений: 11,616
Записей в блоге: 1
29.10.2015, 15:55
1. Клиент-сервер, соединение установлено по TCP. Если одна из сторон закрывает
соединение, другая сторона при попытке чтения или записи получает соответствующий
код ошибки (0 для graceful shutdown, -1 в остальных случаях). Если хэндл сокета
ассоциирован с портом завершения, порт выдает сигнал завершения и его сможет
обработать любой свободный поток из пула.

Если связь между клиентом и сервером была разорвана (например, упала сеть),
то такой сигнал может и не прийти, или прийти, но с большой задержкой.
Здесь возможет вариант с установкой опции keepalive для сокета.
Я несколько раз писал такие серверы на I/O completion ports, мне эта
опция keepalive ни разу не была полезной. Это так, к слову.

2. Когда хэндл, связанный с портом завершения, закрывается (CloseHandle, например),
ассоциация между ним и портом завершения тоже разрывается, а все внутренние
ресурсы, на которые указывал хэндл, очищаются.

Цитата Сообщение от Retyrn0 Посмотреть сообщение
мой сервер при событии отключения выводит сколько активных соединений. Я открываю, скажем, 5 вкладок. Потом все закрываю. Потом открываю новую - сервер выдаёт, что у меня 6 активных подключений.
Это проблема сервера, а не портов завершения или сокетов.
0
45 / 48 / 5
Регистрация: 24.06.2013
Сообщений: 677
29.10.2015, 16:00  [ТС]
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
//---------------------------------------------------------------------------------------------------
//Функция потока сервера для обслуживания порта завершения
//---------------------------------------------------------------------------------------------------
DWORD WINAPI ServerPool(HANDLE hp)
{
    unsigned long bytes;     // Кол-во байтов
    unsigned long key;       // Значение, асоциированное с хендлом порта
    char buffer[128];        // Буфер для сообщений
    LPOVERLAPPED overlapped; // Структура асинхронного I/O
    HANDLE hport=hp;         // Дескриптор порта
    DWORD flags;             // Флаги ф-ции WSARecv()
    while(serverrun) 
    {
        // Получаем информацию о завершении операции
        if(GetQueuedCompletionStatus(hport, &bytes, &key, &overlapped, INFINITE)) 
        {
            printf("-----------------------New operation-----------------------\n");
            // Операция завершена успешно
            Sock*op=(Sock*)overlapped;
            // Определяем тип завершенной операции и выполняем соответствующие действия
            switch(op->type) 
            {
                //Завершена отправка данных
            case Sock::op_type_send:
                delete[]op->buff;
                delete op;
                break;
                //Завершен приём данных
            case Sock::op_type_recv:
                if(!bytes) 
                {
                    //Соединение с данным клиентом закрыто
                    ClientList.remove(op->sock);
                    closesocket(op->sock);
                    strcpy(buffer,"Client %d disconnected, active clients %d\n");
                    printf(buffer,op->numb,ClientList.size());
                    break;
                }
                op->buff[bytes]='\0';
                strcpy(buffer,"From client %d recv message %s\n");
                printf(buffer,op->numb,op->buff);
                Recv(op);
                unsigned long b;
                WSABUF buf;
                buf.buf = op->buff;
                buf.len = BUFF_SIZE;   // buffer_len – постоянная величина 
                if(!WSARecv(op->sock,&buf,1,&b,&flags,op,0))
                {
                    strcpy(buffer,"Error: WSARecv");
                    printf("%s %d\n",buffer, WSAGetLastError());
                }
            }
        }
        else 
        {
            if(!overlapped)
            {
                // Ошибка с портом
                // Закрываем все сокеты, закрываем порт, очищаем список
                for(list<SOCKET>::iterator i=ClientList.begin();i!=ClientList.end();i++)
                {
                    closesocket(*i);
                }
                ClientList.clear();
                closesocket(server_sock);
                CloseHandle(hport);
                strcpy(buffer,"Error: complition port %d, server is stoped\n");
                printf(buffer,GetLastError());
                _getch();
                exit(0);
            }
            else 
            {
                //Закрываем соединение с клиентом
                closesocket(((Sock*)overlapped)->sock);
                ClientList.remove(((Sock*)overlapped)->sock);
                strcpy(buffer,"Client %d disconnected, active clients %d\n");
                printf(buffer,((Sock*)overlapped)->numb,ClientList.size());
            }
        }
    }
    return 0;
}
Добавлено через 2 минуты
Только что в строку 17 добавил вывод на экран текста, чтобы понимать, что возникло завершение чего-либо. При закрытии вкладки сообщение не выводится - порт завершения не запускает пул почему-то. Закрытие вкладки в браузере - наверное не аварийная ситуация? И всё же что-то не работает обработчик. Подскажите пожалуйста, уже мозг кипит. Вроде всё правильно, а не работает.
0
Ушел с форума
Эксперт С++
 Аватар для Убежденный
16481 / 7444 / 1187
Регистрация: 02.05.2013
Сообщений: 11,616
Записей в блоге: 1
29.10.2015, 16:20
Вставьте printf сразу после вызова (не важно, успешного или нет) GetQueuedCompletionStatus.
И еще мне по коду непонятно, зачем здесь вызывается break: ведь после закрытия соединения
рабочие потоки должны продолжать работу...
0
45 / 48 / 5
Регистрация: 24.06.2013
Сообщений: 677
29.10.2015, 16:44  [ТС]
Цитата Сообщение от Убежденный Посмотреть сообщение
Вставьте printf сразу после вызова (не важно, успешного или нет) GetQueuedCompletionStatus.
Как раз так и поступил - в 17 строке стоит принтф. При закрытии вкладки не выводится.
Цитата Сообщение от Убежденный Посмотреть сообщение
И еще мне по коду непонятно, зачем здесь вызывается break: ведь после закрытия соединения
рабочие потоки должны продолжать работу...
Там break стоят для выхода из switch, а не из цикла. Если бы проблема была в этом, то у меня запускается 2 потока на машине и в случае выхода из цикла больше чем 2 раза вкладку открыть не удалось бы.

Добавлено через 1 минуту
Сейчас ещё попробую вставить на не успешный вызов.

Добавлено через 4 минуты
Не помогло. Добавила в конец цикла вывод текста - ничего не пишет при закрытии вкладки.

Добавлено через 2 минуты
А должно выводиться каждый раз при вообще любом событии завершения. Чтение-запись - работает как надо и всё прекрасно, но закрытие вкладки браузера не вызывает события завершения чтения, хотя я так понял должно?
Цитата Сообщение от Убежденный Посмотреть сообщение
Если хэндл сокета
ассоциирован с портом завершения, порт выдает сигнал завершения и его сможет
обработать любой свободный поток из пула.
0
Ушел с форума
Эксперт С++
 Аватар для Убежденный
16481 / 7444 / 1187
Регистрация: 02.05.2013
Сообщений: 11,616
Записей в блоге: 1
29.10.2015, 16:59
Цитата Сообщение от Retyrn0 Посмотреть сообщение
но закрытие вкладки браузера не вызывает события завершения чтения, хотя я так понял должно?
Попробуй тестировать без всех этих браузеров, вкладок и т.п.
Просто через "голые" сокеты обращаться к серверу, писать-читать, а
затем делать shutdown/closesocket.
0
45 / 48 / 5
Регистрация: 24.06.2013
Сообщений: 677
29.10.2015, 17:03  [ТС]
Цитата Сообщение от Убежденный Посмотреть сообщение
Попробуй тестировать без всех этих браузеров, вкладок и т.п.
Просто через "голые" сокеты обращаться к серверу, писать-читать, а
затем делать shutdown/closesocket.
Тоже подумал что стоит грешить на браузер...попробую, но проблема в том, что сервер должен работать именно с браузером. Т.е. даже если мимо браузера всё заработает, то проблема сама собой не решится =(
0
Ушел с форума
Эксперт С++
 Аватар для Убежденный
16481 / 7444 / 1187
Регистрация: 02.05.2013
Сообщений: 11,616
Записей в блоге: 1
29.10.2015, 17:06
Да я понимаю. Но все-таки начинать нужно с главного: голый клиент + голый сервер.
И отлаживаться сперва на такой схеме, а уже потом подключать сложности в виде
браузеров, прокси, разрывов сети и т.п.
1
45 / 48 / 5
Регистрация: 24.06.2013
Сообщений: 677
29.10.2015, 17:10  [ТС]
Цитата Сообщение от Убежденный Посмотреть сообщение
Да я понимаю. Но все-таки начинать нужно с главного: голый клиент + голый сервер.
И отлаживаться сперва на такой схеме, а уже потом подключать сложности в виде
браузеров, прокси, разрывов сети и т.п.
Тоже верно. Спасибо, буду вертеть. Когда доделаю, выложу, может кому в будущем пригодится.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
29.10.2015, 17:10
Помогаю со студенческими работами здесь

Чтение из COM порта, При чтении из порта зависает read()
Каждому рано или поздно приходится программировать com порт. Вот и мой черед пришол. Я ужу умею: Откривать,закривать, писать. а читать не...

Утечки при работе с динамической памятью
Здравствуйте, отправляю задачу на сервер, пишут:&quot;Утечки памяти&quot;. Для входных данных: 3 Вот код: #include &lt;stdio.h&gt; #include...

Битовые утечки при записи данных на диск
Доброго дня форумчане! Сорри если оффтоп но... Пишу в консольке на C++ (MSVCE 2010) различные движки по расчетам и тут столкнулся с...

ClientDataSet, Blob утечки памяти при записи в файл
столкнулся с такой ситуацией, есть ClientdataSet в котором есть блоб поле, которое я записываю процедурой ниже: Procedure...

Избежать утечки памяти при преобразовании строки в массив символов
Всем привет! Как избежать утечки памяти в таком коде: char* ConvertString(String input) { char *output = new char; ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
13
Ответ Создать тему
Опции темы

Новые блоги и статьи
WordPad для Windows 11
Jel 10.01.2026
WordPad для Windows 11 — это приложение, которое восстанавливает классический текстовый редактор WordPad в операционной системе Windows 11. После того как Microsoft исключила WordPad из. . .
Classic Notepad for Windows 11
Jel 10.01.2026
Old Classic Notepad for Windows 11 Приложение для Windows 11, позволяющее пользователям вернуть классическую версию текстового редактора «Блокнот» из Windows 10. Программа предоставляет более. . .
Почему дизайн решает?
Neotwalker 09.01.2026
В современном мире, где конкуренция за внимание потребителя достигла пика, дизайн становится мощным инструментом для успеха бренда. Это не просто красивый внешний вид продукта или сайта — это. . .
Модель микоризы: классовый агентный подход 3
anaschu 06.01.2026
aa0a7f55b50dd51c5ec569d2d10c54f6/ O1rJuneU_ls https:/ / vkvideo. ru/ video-115721503_456239114
Owen Logic: О недопустимости использования связки «аналоговый ПИД» + RegKZR
ФедосеевПавел 06.01.2026
Owen Logic: О недопустимости использования связки «аналоговый ПИД» + RegKZR ВВЕДЕНИЕ Введу сокращения: аналоговый ПИД — ПИД регулятор с управляющим выходом в виде числа в диапазоне от 0% до. . .
Модель микоризы: классовый агентный подход 2
anaschu 06.01.2026
репозиторий https:/ / github. com/ shumilovas/ fungi ветка по-частям. коммит Create переделка под биомассу. txt вход sc, но sm считается внутри мицелия. кстати, обьем тоже должен там считаться. . . .
Расчёт токов в цепи постоянного тока
igorrr37 05.01.2026
/ * Дана цепь постоянного тока с сопротивлениями и напряжениями. Надо найти токи в ветвях. Программа составляет систему уравнений по 1 и 2 законам Кирхгофа и решает её. Последовательность действий:. . .
Новый CodeBlocs. Версия 25.03
palva 04.01.2026
Оказывается, недавно вышла новая версия CodeBlocks за номером 25. 03. Когда-то давно я возился с только что вышедшей тогда версией 20. 03. С тех пор я давно снёс всё с компьютера и забыл. Теперь. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru