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

      я уже думал за сабж и тоже скланяюсь к такому решению
      но сначала shutdown() попробую

      Цитата Oleg2004 @
      Ссылочку не дадите?

      увы... было много лет назад. но читал в какой то толстой книге по сетевому программированию в виндовс.

      Цитата Oleg2004 @
      Можно ведь и не самописный сервер использовать, а пробовать коммерческую версию, если деньги есть.

      я не смог найти.

      Цитата Oleg2004 @
      Или поднять еще один сервер и балансировать нагрузку.

      у меня их уже 5 штук. по 7 тысяч онлайн на каждом.
      я бы взял еще больше но тупа нету в стойке места. Мы и так 20 серверов отжали )
        progman, а почему ты сделал все на голом API? Чем варинат с boost.asion не устроил?
          Цитата progman @
          Цитата Oleg2004 @
          Ссылочку не дадите?

          увы... было много лет назад. но читал в какой то толстой книге по сетевому программированию в виндовс.

          Вероятно, речь идёт о:
          "Программирование серверных приложений для Windows 2000".
          Джеффри Рихтер, Джейсон Кларк.
          Можно найти в электронном виде.
            Цитата progman @
            у меня их уже 5 штук. по 7 тысяч онлайн на каждом.

            Ну ни хрена себе втихую от нас :D такие проекты девелопите...респект.
            Цитата ЫукпШ @
            Вероятно, речь идёт о:
            "Программирование серверных приложений для Windows 2000".

            Спасибо буду искать.
            Нашел - правда качество жуть, пришлось помучиться с преобразованием в doc.
            Много интересного для себя нашел.
            Здесь только о порте завершения самое главное.
            Прикреплённый файлПрикреплённый файлIOCP.doc (448 Кбайт, скачиваний: 176)
            Файлик малость подправил - даже оригинал в дэжавю такого качества что порой не разберешь.
            Самое главное, что здесь Рихтер рассказал - это поведение рабочих потоков, выполняющих
            GetQueuedCompletionStatus в цикле. И там есть свои заморочки однако.
            Сообщение отредактировано: Oleg2004 -
              Цитата shm @
              progman, а почему ты сделал все на голом API? Чем варинат с boost.asion не устроил?

              6 лет назад планировался маленький сервер на 1000 коннектов ( три раза ога ) и про буст я не знал.
              когда все уже разраслось я тупо не смог найти адекватного серверного прогера который все переписал бы по человечески.
              Была попытка на node.js уйти но тоже провалилась - не нашел квалифицированных кадров.

              в итоге плюнул и серверную часть тяну сам на сях на голом апи. Хотя задолбался уже.
              Сообщение отредактировано: Oleg2004 -
                Цитата progman @
                Объект подлежащий удалению сливается в список на удаление который обрабатывается в потоке 17
                Так вот, если в потоке 17 вызвать closesocket то в одном из потоков 1-16 GetQueuedCompletionStatus срабатывает и возвращает значение TRUE или FALSE а также lpNumberOfBytes вернет ноль но самое страшное что в поле lpOverlapped будет указание на структуру сокета, который был закрыт и объект удален и самое нехорошее что это происходит не всегда. Иногда вызывается обработчик в GetQueuedCompletionStatus а иногда нет.

                Все последнее время посвятил разбирательству механизмов связанных с IOCP.
                Тем более что отслеживаю ветку progman'a про буст, и там тоже не все так просто.
                Поэтому возвращаюсь опять в эту тему.
                Попробую еще раз порассуждать на эту тему.
                1. Итак, в 16-ти рабочих потоках крутятся (бесконечно висим)на GetQueuedCompletionStatus() - ну, если поток не работает (т.е. не проскочил уже свой вызов и не осуществляет обработку.)
                2. Если во время обработки вызова GetQueuedCompletionStatus() в каком-то из потоков 1-16 lpNumberOfBytes вернет ноль, то этот же рабочий поток должен cам закрыть сокет - так как возвращенный нуль всегда трактуется как пришедший с той стороны FIN. Именно такой вариант закрытия сокета просматривается во всех примерах исходников.
                3. В случае варианта progman'a решение о закрытии сокета принимается специальным 17-тым потоком. Т.е. это внешнее закрытие, происходящее вне компетенции объекта IOCP. И это скорее всего как раз таки решение о закрытии сокета из-за таймаута, так как клиент наверное отпал. Но тут одна загвоздка. Сокет был ассоциирован с портом завершения, и сlosesocket(), выполненный не в рабочем потоке, ассоциацию эту по видимому не удаляет.
                4. Нашел в сети такую последовательность закрытия сокета:
                ExpandedWrap disabled
                  shutdown(sock->socket,SD_BOTH);
                  closesocket(sock->socket);
                  sock->socket = INVALID_SOCKET;

                Может именно ее надо применять?
                И теперь структура overlapped, указатель на которую может по каким-то причинам остаться в системном пакете очереди завершения, будет содержать инвалидный сокет, что и даст понимание для GetQueuedCompletionStatus() и она сработает совсем с другой ошибкой, что позволит правильно идентифицировать проблему.
                Вот кстати и косвенное подтверждение моих предположений:
                Цитата
                The IOCP documentation says that application needs to call CloseHandle() to unregister the socket from the IOCP, and PJLIB does this in ioqueue_winnt.c.
                We assumed that a call to CloseHandle() should close the socket (just like closesocket()), since a socket should just be another handle in Windows NT.
                But turns out this is not the case. A call to CloseHandle() doesn't seem to close the socket, as the socket still appears in "netstat" output. Also further down it will cause "Invalid handle" exception to be raised in debug mode when WSACleanup() is called.
                Checking at MSDN documentation about CloseHandle() (see ​http://msdn.microsoft.com/en-us/library/ms...11(VS.85).aspx), actually it does suggest application to call both for socket, i.e. always follow closesocket() call with CloseHandle(). This is what it says:
                After closing a socket using the closesocket function, ensure that you release the socket by calling CloseHandle. For more information, see ​Socket Closure.
                Сообщение отредактировано: Oleg2004 -
                  Цитата Oleg2004 @
                  ...
                  4. Нашел в сети такую последовательность закрытия сокета:
                  shutdown(sock->socket,SD_BOTH);
                  closesocket(sock->socket);
                  sock->socket = INVALID_SOCKET;
                  Может именнно ее надо применять?

                  Тут сразу такое предложение:
                  если "sock" в данном случае экземпляр класса-сокета,
                  оболочка вокруг "socket", тогда просто напрашивается
                  решение делать эти операции функциями самого класса.
                  Которые будут вызваны функцией "Uninstall".
                  Которая может быть вызвана из деструктора.
                    И еще одно рассуждение на эту тему.
                    Цитата progman @
                    если в потоке 17 вызвать closesocket то в одном из потоков 1-16 GetQueuedCompletionStatus срабатывает

                    Как closesoсket()??? в потоке №17 может вызвать срабатывание одной из функций GetQueuedCompletionStatus, которые крутятся в рабочих потоках 1-16, ассоциированных с IOCP и ПОЛНОСТЬЮ! им же управляемых?
                    Есть четкий перечень функций АПИ, которые могут сформировать системный пакет о завершении I/O c четырьмя полями:
                    dwBytesTransferred
                    dwCompletionKey
                    pOverlapped
                    dwError
                    в очередь IOCP
                    Это только
                    • ConnectNamedPipe()
                    • DeviceIoControl()
                    • LockFileEx()
                    • ReadDirectoryChangesW()
                    • ReadFile()
                    • TransactNamedPipe()
                    • WaitCommEvent()
                    • WriteFile()
                    • WSASendMsg()
                    • WSASendTo()
                    • WSASend()
                    • WSARecvFrom()
                    • WSARecvMsg()
                    • WSARecv()
                    Только ЭТИ - функции способны по своем завершении создать системный пакет о завершении.
                    Как видим, closesocket()в списке нет :)
                    Эта функция вообще не имеет отношения к операциям ввода-вывода на пользовательском уровне.
                    Так в чем же дело?
                    Это просто предположение.
                    GetQueuedCompletionStatus и closesocket исполняются в разных потоках. Рабочие потоки полностью управляются объектом IOCP, а closesocket выполняется в полностью отдельном потоке. Но и там и там - есть один и тот же объект и его характеристики - это клиентский сокет, он является так сказать общим ресурсом. Как этот доступ осуществляется - сие науке неизвестно. Вполне возможен побочный эффект в виде потоконебезопасности, который проявляется при определенном стечении обстоятельств.
                    И теперь про это самое стечение.
                    progman ничего не сообщил о том, в результате каких условий поток №17 принимает решение о закрытии клиентского сокета. Предположим, что это решение принимается по таймауту, когда клиентский сокет вообще заснул (или отвалился вообще).
                    Что это означает в отношении IOCP?
                    Это означает, что ни один из рабочих потоков не обрабатывал долгое время свои же вызовы WSARecv() (они наверняка понатыканы в каждом рабочем потоке). Нет вызова WSARecv() в каком то рабочем потоке - IOCP не назначит другой ожидающий поток на обработку записи о завершении этой операции - ее просто нет. Тем не менее есть пул рабочих потоков - которые висят в цикле GetQueuedCompletionStatus, но и им пакет завершения не может достаться, потому что его просто не существует.
                    Ну блин и где разгадка этого пазла???
                    Думаю все-таки где-то программно-архитектурная клизма...
                    По теории так быть не может.
                    Сообщение отредактировано: Oleg2004 -
                      Короче, прошу progman'a не оставить нас без своего участия в поиске столь интересной :wall: :wall: :wall: проблемы...
                        Цитата Oleg2004 @
                        Ну блин и где разгадка этого пазла???

                        Для начала, я бы попробовал уничтожать сокет не из 17-го потока.
                        Эта ничтожная операция не требует больших затрат, а значит
                        можно использовать 16 используемых потоков.
                        В случае принудительной ликвидации сокета, я бы использовал
                        "PostQueuedCompletionStatus" и затем уничтожал сокет в обработчике
                        рабочего потока.
                          Цитата Oleg2004 @
                          progman ничего не сообщил о том, в результате каких условий поток №17 принимает решение о закрытии клиентского сокета. Предположим, что это решение принимается по таймауту, когда клиентский сокет вообще заснул (или отвалился вообще).
                          Что это означает в отношении IOCP?

                          Ну например вход второго клиента под таким же логином.
                          В этом случае оба клиента активны и "гонят" трафик.
                          По логике системы оба должны быть дисконнектнуты.

                          с переходом на boost.asion проблема рассосалась.
                            Цитата progman @
                            boost.asion

                            asio, не размножай мою опечатку. :)
                              Цитата progman @
                              с переходом на boost.asion проблема рассосалась.

                              У кого рассосалась, а у кого и нет... :(
                              Цитата progman @
                              В этом случае оба клиента активны и "гонят" трафик.
                              По логике системы оба должны быть дисконнектнуты.

                              Ну вот после этого стало более менее ясно.
                              Клиентский трафик через сокет идет, а поток 17 решает убить сокет с активными операциями.
                              Теперь после такого разъяснения все вроде бы встает на место.
                              Скорее всего это баг архитектуры приложения, не учитывающий взаимоотношения пакетов завершения рабочих потоков с проблемами закрытия (принудительного по сути) сокетов с активным трафиком. Ясен день, что в HTTP такой ситуации не может возникнуть по определению. Все решает пользовательский протокол. А его знает только
                              progman :yes:
                              Так что виндовское АПИ тут не причем... :yes: :no-sad:
                              Ух...а то я уж стал грешить на микрософт. Не, у них все Ок.
                              Сообщение отредактировано: Oleg2004 -
                                Цитата Oleg2004 @
                                Скорее всего это баг архитектуры приложения, не учитывающий взаимоотношения пакетов завершения рабочих потоков с проблемами закрытия (принудительного по сути) сокетов с активным трафиком. Ясен день, что в HTTP такой ситуации не может возникнуть по определению. Все решает пользовательский протокол.

                                Логичное предположение с совершенно невероятным и неожиданным выводом.
                                "..не учитывающий взаимоотношения пакетов завершения рабочих потоков с проблемами закрытия.." -
                                другими словами, отсутствует синхронизация между работой очереди запросов обслуживания сокета
                                и принудительным уничтожением сокета.
                                Для этого как раз можно предложить не копаться в протоколе, а произвести синхронизацию.
                                Посредством размещения запроса на уничтожение сокета в очереди запросов порта завершения.
                                  Цитата ЫукпШ @
                                  другими словами, отсутствует синхронизация между работой очереди запросов обслуживания сокета
                                  и принудительным уничтожением сокета.

                                  собственно ее и сейчас нет.
                                  в потоке 17 просто закрываю порт. Буст видимо внутри сам все разруливает как то - но деструктор коннектора вызывается практически мгновенно.
                                  0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                  0 пользователей:
                                  Страницы: (6) « Первая ... 2 3 [4] 5 6  все


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