На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Страницы: (6) « Первая ... 3 4 [5] 6  все  ( Перейти к последнему сообщению )  
    > I/O Completition Port проблемы с удалением OVERLAPPED объектов
      Цитата progman @
      собственно ее и сейчас нет.
      в потоке 17 просто закрываю порт. Буст видимо внутри сам все разруливает как то ...

      А он (Буст) точно использует порт завершения ?
      Насколько я понимаю, это кросс-платформенная библиотека.
      Это значит, что все исходники и под Линукс (теоретически) можно откомпилировать
      и собрать версию сервера для Линукс. А там нет порта завершения а-ля Виндус,
      значит всё придётся мастерить как-то иначе. Тогда какой смысл вообще использовать
      эти технологии ?
      ---
      В этой истории постоянно преследует чувство
      глубокого неудовлетворения.. :huh:
      Во первых, одна и та-же функция, "CreateIoCompletionPort", используется для
      разных операций.
      Второе - ещё хуже.
      После установки ассоциации порта завершения и хэндла объекта, совершенно
      не понятно, как правильно разорвать эту ассоциацию.
      Как я понял, это и есть проблема данного обсуждения - сокет закрыт,
      а его хэндл остался где-то в списке порта. И приходят запросы на обслуживание
      уже давно закрытого сокета.
      Сообщение отредактировано: ЫукпШ -
        Цитата ЫукпШ @
        Посредством размещения запроса на уничтожение сокета в очереди запросов порта завершения.

        Такого запроса не существует, увы, для порта завершения.
        Даже PostQueuedCompletionStatus, который просто эмулирует пакет завершения.
        Цитата progman @
        в потоке 17 просто закрываю порт.

        Это каким таким образом вы закрываете порт? Чей порт?
        Порт приложения? :wacko:
        Или вы удаляете запись из таблицы TCP-соединений с помощью SetTcpEntry() и переводите TCP-соединение в MIB_TCP_STATE_DELETE_TCB – т.е. удалить запись из таблицы, тем самым разорвать соединение.
        Потому что я честно не понимаю как вы "просто закрываете порт." <_<
        Можете привести кусочек кода?
        Сообщение отредактировано: Oleg2004 -
          Цитата ЫукпШ @
          значит всё придётся мастерить как-то иначе

          На пользовательском уровне ничего менять не надо. Внутри буст сам подключит нужные библиотеки для нужной ОС.
            Цитата ЫукпШ @
            Как я понял, это и есть проблема данного обсуждения - сокет закрыт, а его хэндл остался где-то в списке порта. И приходят запросы на обслуживание уже давно закрытого сокета.

            Приходится работать телепатом, потому что progman выдает не секреты своего приложения, которое обслуживает 17000 пользователей???.
            Я квалифицирую проблему несколько иначе.
            Как написал ТС, у приложения в потоке 17 вдруг возникло желание убить какого-то активного - т.е. обменивающегося запросами пользователя.
            Раз очередь запросов I/O в порте завершения огромна - не зря ее обслуживают 16 рабочих потоков, после убиения клиента и его сокета в очереди порта завершения находятся еще не обслуженные запросы от этого пользователя. Как пишет сам ТС,
            Цитата progman @
            В данный момент этот 1234 может из порта что то читать или что то писать или вообще заниматься обработкой своих внутренних данных

            далее он же пишет
            Цитата progman @
            При этом после закрытия сокета и удаления объекта 1234 в рабочем потоке может произойти вызов GetQueuedCompletionStatus а может и не произойти - я закономерность не понимаю. Она по разному себя ведет.

            На самом деле она ведет себя везде и всегда одинаково.
            Есть только два варианта.
            1. Сокет закрыли - случайно удачно - тогда, когда от пользователя ничего не было. В очереди пакетов завершения от этого пользователя нет ничего. Тогда все проходит Ок, сокет убивается и больше от этого пользователя мы в очереди ничего не увидим.
            2. Сокет убили - но в очереди пакетов завершения - совершенно в непонятном месте длиннейшей очереди - остался хоть один пакет завершения для этого сокета. И это моментально создает проблему. Пакет завершения к примеру WSARecv() для этого клиента в очереди еще есть, и когда-то какой-то рабочий поток выполнит вызов GetQueuedCompletionStatus - для этого пакета уже убитого сокета.
            И как пишет progman,
            Цитата
            GetQueuedCompletionStatus выдаст в поле *lpOverlapped только что удаленный объект. "только что" понятие тут растяжимое может вызваться через миллисекунду а может через 3 секунды ( у меня рекорд 5 секунд был ).

            Именно поэтому время проявления проблемы совершенно случайно - до 5 секунд.
            Как я понимаю, progman эту проблему в общем то понял, и пытался ее как-то решить:
            Цитата progman @
            В потоке который обрабатывает очередь объектов на удаление я у каждого объекта уточняю статус с помощью макроса HasOverlappedIoCompleted и удаляю только те у кого нет в обработке операций
            , он пытается понять, есть ли в очереди пакеты для убитого клиента.
            Но почему-то это у него не получилось.
            К примеру и поэтому может не произойти - HasOverlappedIoCompleted вызывается один раз наверно, а в очереди к примеру болтаются в разных местах 2 пакета...
            В общем, пока архитектура приложения и даже его предназначение нам неизвестно, помочь ТС-у будет практически невозможно, пишем 5-ю страницу уже и все мимо.
            Хотя мне в общем то проблема понятна - убивать живого клиента можно лишь убедившись что это возможно.
            PS
            И, насколько я знаю, закрыть порт, на котором работает сервер - это просто его выключить. Потому как порт однозначно определяет приложение. О каком порте идет речь у ТС?
            Сообщение отредактировано: Oleg2004 -
              Цитата ЫукпШ @
              А он (Буст) точно использует порт завершения ?
              Насколько я понимаю, это кросс-платформенная библиотека.

              под виндой 146% - я под отладчиком видел внутри вызовы виндовых функций.

              Цитата ЫукпШ @
              Как я понял, это и есть проблема данного обсуждения - сокет закрыт,
              а его хэндл остался где-то в списке порта. И приходят запросы на обслуживание
              уже давно закрытого сокета.

              ага. Это и было непонятным местом и из-за этого я свалил на boost.asio

              Цитата Oleg2004 @
              Это каким таким образом вы закрываете порт? Чей порт?
              Порт приложения?

              некорректно выразился. В потоке 17 я просто вызываю closesocket для сокетов двух клиентов которые внезапно залогинились род одним и тем же логином.
              Или пришел сигнал от модератора кикнуть из онлайна определенную группу аккаунтов.

              Добавлено
              Oleg2004 в #64 вы все правильно описали
              Цитата Oleg2004 @
              Хотя мне в общем то проблема понятна - убивать живого клиента можно лишь убедившись что это возможно.

              к своему стыду мне не удалось придумать надежного механизма как это обеспечить. В итоге и стал шаманить с сначала 30 секундной задержкой перед убиванием сокета а потом и с пятиминутной.
              Ну и в итоге как вы знаете уже махнул рукой и за пару часов переписал на boost.asio получилось. 168 часов без сбоев сейчас сервак висит.
              Сообщение отредактировано: Oleg2004 -
                Цитата progman @
                168 часов без сбоев сейчас сервак висит.

                Во блин...невезуха. :(
                Но разрулить это на бусте будет посложнее.
                  Цитата Oleg2004 @
                  Во блин...невезуха.

                  а я думаю наобород - это же прекрасно что больше недели ни одного сбоя )))))
                    Не понял. :wacko:
                    Вы же написали, что:
                    Цитата progman @
                    сейчас сервак висит.

                    Завис, повис - т.е. не пашет :blink:
                    Наверно опять неточно выразились :D
                    Ну а по теме - проблема решается достаточно просто.
                    Для того сокета, который надо закрыть, сначала выполняется shutdown на прием, таким образом от кривых клиентов ничего больше приниматься не будет.
                    И если в системе вдруг еще остались пакеты завершения для операции WSASend() по этому сокету, то после небольшого таймаута можно делать shutdown на передачу и затем - если надо, еще махонький таймаут - и closesocket.
                    Конечно же было эффективнее отловить точно момент обработки последнего WSASend() по этому сокету - и потом сразу делать closesocket.
                    Я бы делал как-то так примерно... :D
                      Цитата Oleg2004 @
                      Завис, повис - т.е. не пашет

                      висит работает. проблем нет )
                      сорри за кривой русский. :crazy:

                      Цитата Oleg2004 @
                      Для того сокета, который надо закрыть, сначала выполняется shutdown на прием, таким образом от кривых клиентов ничего больше приниматься не будет.

                      я делал. Вы мне пару страниц назад это посоветовали.
                      только я и на прием и на отправку сразу шотдаунил.
                      потом таймаут 5 минут и удалял
                      и вот после шотдауна 5 минут раз в день не хватало.....
                        Цитата progman @
                        и вот после шотдауна 5 минут раз в день не хватало.....

                        Ничего себе...это сколько же надо пакетов иметь в очереди порта, чтобы 16 рабочих потоков не могли разрулить пару пакетов за 5 минут :wall:
                        Не могу себе представить...где-то еще какая-то клизма... :(
                        Сообщение отредактировано: Oleg2004 -
                          Цитата Oleg2004 @
                          Цитата progman @
                          и вот после шотдауна 5 минут раз в день не хватало.....

                          Ничего себе...это сколько же надо пакетов иметь в очереди порта, чтобы 16 рабочих потоков не могли разрулить пару пакетов за 5 минут :wall:
                          Не могу себе представить...где-то еще какая-то клизма... :(

                          не знаю.
                          По счетчикам пакетов у меня больше 10 тысяч входящих пакетов в минуту не было.
                          В среднем 7-8 тысяч входящих в минуту. При среднем времени на обработку одного пакета в 7-10мс.
                          Собственно это ниачем для IOCP

                          поэтому я не знаю wtf
                          Сообщение отредактировано: progman -
                            Цитата shm @
                            Цитата ЫукпШ @
                            значит всё придётся мастерить как-то иначе

                            На пользовательском уровне ничего менять не надо. Внутри буст сам подключит нужные библиотеки для нужной ОС.

                            В этом сомнений нет.
                            Это разработчикам Буста придётся решать вопрос иначе, те фактически
                            на сокетах беркли. А раз такое возможно, зачем нужен порт завершения ?
                            ---
                            Делаем приблизительно так:
                            1. Первый поток принимает входящие соединения.
                            Принимает решение о создании объекта-клиента и создаёт его.
                            Заносит указатель в оболочку из потоко-безопасного шаред-пойнтера.
                            2. Второй поток - диспетчер. Выполняет (частично) функции порта завершения.
                            Экземпляр клиента размещается в его списке.
                            3. N объектов-рабочих потоков созданы заранее. Рабочий поток ожидает семафора функцией ожидания.
                            Имеется очередь (потокобезопасная) шаред-пойнтеров на клиенты.
                            Максимальное значение счётчика семафора равно размеру очереди запросов
                            на обслуживание.
                            4. Диспетчер определяет статусы клиентов функцией select.
                            Если имеется активность у конкретного клиента, клиент передаётся потоку.
                            В очередь. С увеличением счётчика семафора.
                            Поток выбираем из массива потоков по минимально загруженной очереди.
                            5. Рабочий поток просыпается семафором, выбирает клиента (тоже в шаред-пойнтер),
                            запускает ему функцию Run. После выполнения задачи уничтожает клиента и выполняет "wait".
                            Поскольку число ссылок на объект ещё не 0, фактически клиен ещё не будет уничтожен.
                            6. Если клиента надо уничтожить принудительно, сделаем запрос об этом диспетчеру.
                            Тут тоже должна быть очередь - очередь запросов на уничтожение.
                            Диспетчер уничтожит объект, синхронно со своими манипуляциями над сокетами.
                            Если объект ещё в очереди рабочего потока или даже в обработке,
                            он будет обслуживаться обычным образом. Но по окончании будет уничтожен рабочим потоком.
                            Тоже синхронно.
                            Это всё.
                            ---
                            Это задача на шаред-пойнтер и очередь.
                            Чтобы иметь возможность использовать сервер для клиентов другого типа,
                            мастерим его как шаблон.
                            Сообщение отредактировано: ЫукпШ -
                              Цитата ЫукпШ @
                              Это разработчикам Буста придётся решать вопрос иначе, те фактически
                              на сокетах беркли. А раз такое возможно, зачем нужен порт завершения ?

                              В asio несколько внутренних реализаций. Под windows используется IOCP, под linux - epoll.
                                Цитата ЫукпШ @
                                Делаем приблизительно так:

                                Велосипед с квадратными колесами. По сути Kray74 правильно ответил.
                                  Цитата progman @
                                  В среднем 7-8 тысяч входящих в минуту.

                                  Ни фига себе...это что же за приложение такое популярное? :lol:
                                  Цитата progman @
                                  В среднем 7-8 тысяч входящих в минуту.

                                  Это то что разруливается WSARecv().
                                  А сколько еще исходящих WSASend().
                                  Ясно что система работает практически на грани возможностей IOCP.
                                  На мой взгляд (со стороны :) ) нужна система с балансировкой серверов.
                                  Хотя у вас типа уже и нет возможностей (стойка маленькая :D )
                                  Сообщение отредактировано: Oleg2004 -
                                  0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                  0 пользователей:


                                  Рейтинг@Mail.ru
                                  [ Script execution time: 0,0842 ]   [ 17 queries used ]   [ Generated: 29.03.24, 09:50 GMT ]