На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
  
    > I/O Completition Port проблемы с удалением OVERLAPPED объектов
      Ситуация такая - есть объект унаследованный от OVERLAPPED, который ассоциируется портом завершения.

      Я столкнулся с ситуацией разрулить которую никак не могу:
      объекты уходят на удаление в двух случаях:
      - GetQueuedCompletionStatus вернул FALSE или *lpNumberOfBytes вернулось ноль
      - внутренняя серверная логика приняла решение что клиент должен быть дисконнектнут

      Схема удаления объекта выглядит так:
      - все что подлежит удалению заносится в список на удаление.
      - по тику таймера этот список проверяется
      - если у объекта из списка макрос HasOverlappedIoCompleted возвращает FALSE такой объект не удаляется, список проверяется дальше.
      - если HasOverlappedIoCompleted возвращает TRUE то сначала закрывается сокет ( вызов closesocket ) и потом удаление самого объекта и стирание его из списка.

      проблема в том что накапливается очень быстро большое число объектов для которых HasOverlappedIoCompleted всегда возвращает FALSE
      вызов CancelIO не помогает.
        А если через GetQueuedCompletionStatus попробовать?
          Цитата progman @
          вызов CancelIO не помогает.

          CancelIO надо вызывать из того же потока, который эту IO инициировал.

          Добавлено
          И да, если закрыть сокет, то все pending IO обязательно отменятся с соответствующим кодом ошибки.

          Добавлено
          Цитата progman @
          проблема в том что накапливается очень быстро большое число объектов для которых HasOverlappedIoCompleted всегда возвращает FALSE

          Это скорее всего клиенты с невыполненным WSARecv() на сервере, которые не торопятся слать байты, или вообще отвалились.
          Сообщение отредактировано: Pacific -
            Цитата shm @
            А если через GetQueuedCompletionStatus попробовать?

            Она крутится в рабочем потоке. не уверен что приемлемо ее вызывать из потока в котором объекты киляются для определения статуса.

            Цитата Pacific @
            CancelIO надо вызывать из того же потока, который эту IO инициировал.

            я в курсе. и есть еще CancelIOEx
            но все равно не решает проблему (

            Цитата Pacific @
            И да, если закрыть сокет, то все pending IO обязательно отменятся с соответствующим кодом ошибки.

            Это рождает каскад других побочных проблем - в частности оъект на удаление может и дважды и трижды попасть в список.
            в общем начинается адЪ с многопоточностью - я отказался от этого и закрываю сокет непосредственно перед удалением объекта
            Сообщение отредактировано: progman -
              Цитата progman @
              не уверен что приемлемо ее вызывать из потока в котором объекты киляются для определения статуса.

              Почему?
                Цитата progman @
                в частности оъект на удаление может и дважды и трижды попасть в список.

                Вот с этого и надо начать все разгребать. Простой атомарный флаг "объект в расстрельном списке" решает проблему. Удалось атомарно поменять 0 на 1 - значить можно спокойно вызвать closesocket прямо там же и поместить объект в список.
                  Цитата Pacific @
                  Цитата progman @
                  в частности оъект на удаление может и дважды и трижды попасть в список.

                  Вот с этого и надо начать все разгребать. Простой атомарный флаг "объект в расстрельном списке" решает проблему. Удалось атомарно поменять 0 на 1 - значить можно спокойно вызвать closesocket прямо там же и поместить объект в список.

                  ситуация:
                  внутри объекта произошла ошибка и он помещается в список на "расстрел" при этом вызывается закрытие сокета
                  далее три варианта:
                  - все будет нормально и объект удалится без последствий для системы и вызов GetQueuedCompletionStatus не произойдет
                  - после закрытия сокета но до момента удаления сработает GetQueuedCompletionStatus и выдаст что у этого объекта ноль байт в приемнике и он снова будет помещен в очередь на удаление
                  - после закрытия сокета и после удаления сработает GetQueuedCompletionStatus и выдаст или ошибку по этому объекту или то что у него в приемнике ноль байт и уже удаленный объект будет помещен в очередь на удаление
                  Сообщение отредактировано: progman -
                    Цитата progman @
                    Это рождает каскад других побочных проблем - в частности оъект на удаление может и дважды и трижды попасть в список.

                    А пометить его никак нельзя?
                      Цитата shm @
                      Цитата progman @
                      Это рождает каскад других побочных проблем - в частности оъект на удаление может и дважды и трижды попасть в список.

                      А пометить его никак нельзя?

                      что значит пометить? факт помещения объекта в очередь на удаление разве не метка?
                      или имеется ввиду после удаление хранить его адрес в списке удаленных?

                      вся проблема исключительно в том что закрытие сокета у объекта иногда приводит иногда не приводит к срабатыванию GetQueuedCompletionStatus в рабочем потоке для этого объекта.
                      Сообщение отредактировано: progman -
                        Цитата progman @
                        факт помещения объекта в очередь на удаление разве не метка?

                        Ну раз у тебя один и тот же объект 2 раза в очередь попадает, то значит нет.
                          А, теперь понятно. В моем типовом коде IOCP сервере есть счетчик pending IO операций. Когда вызываю WSASend/WSARecv/AcceptEx/DisconnectEx, счетчик увеличивается, когда получаю результат через GetQueuedCompletionStatus, счетчик уменьшается. Если счетчик стал равен 0 и объект помечен на удаление, то он удаляется (на самом деле не удаляется, а зачищается от старых данных и помещается в пул свободных объектов).

                          Добавлено
                          Так что просто помечай на удаление, вызывай closesocket + считай, сколько там осталось pending IO.
                            Цитата shm @
                            Цитата progman @
                            факт помещения объекта в очередь на удаление разве не метка?

                            Ну раз у тебя один и тот же объект 2 раза в очередь попадает, то значит нет.

                            у меня есть хак - есть список всех когда либо созданных в системе объектов
                            после удаления он из списка выбывает. Перед попыткой удалить идет проверка - есть ли объект в списке или нет.

                            жопа в том что после удаления уже нет никакой возможности понять что это повторное удаление объекта

                            Добавлено
                            Цитата Pacific @
                            А, теперь понятно. В моем типовом коде IOCP сервере есть счетчик pending IO операций. Когда вызываю WSASend/WSARecv/AcceptEx/DisconnectEx, счетчик увеличивается, когда получаю результат через GetQueuedCompletionStatus, счетчик уменьшается. Если счетчик стал равен 0 и объект помечен на удаление, то он удаляется (на самом деле не удаляется, а зачищается от старых данных и помещается в пул свободных объектов).

                            Добавлено
                            Так что просто помечай на удаление, вызывай closesocket + считай, сколько там осталось pending IO.

                            чем это будет отличаться от проверки HasOverlappedIoCompleted которая у меня есть и которая не надежно работает ?

                            Более того мы можем 10 раз вызвать WSARecv и получить все данные за дин вызов. Как корректно счетчик тогда вести?
                            Сообщение отредактировано: progman -
                              progman
                              HasOverlappedIoCompleted вообще не необходимости использовать. GetQueuedCompletionStatus в любом случае вернет результат операции, либо когда она сама завершится, либо будет отменена из-за closesocket. Кстати, у тебя на один объект только один OVERLAPPED буфер ("объект унаследованный от OVERLAPPED")? Тогда тебе категорически нельзя вызывать любые overlapped операции с объектом, если текущая не завершилась. Может в этом проблема?

                              Добавлено
                              Цитата
                              Any pending overlapped send and receive operations ( WSASend/ WSASendTo/ WSARecv/ WSARecvFrom with an overlapped socket) issued by any thread in this process are also canceled. Any event, completion routine, or completion port action specified for these overlapped operations is performed. The pending overlapped operations fail with the error status WSA_OPERATION_ABORTED.

                              Все должно работать со связкой closesocket -> GetQueuedCompletionStatus. Если не работает - у тебя баг где-то значит.

                              Добавлено
                              Цитата progman @
                              Более того мы можем 10 раз вызвать WSARecv и получить все данные за дин вызов. Как корректно счетчик тогда вести?

                              Тогда GetQueuedCompletionStatus вернется 10 раз, по одному на каждый вызов. На каждый вызов (если они идут параллельно) надо передавать отдельную структуру OVERLAPPED!
                              Сообщение отредактировано: Pacific -
                                Цитата progman @
                                чем это будет отличаться от проверки HasOverlappedIoCompleted которая у меня есть и которая не надежно работает ?

                                Возможно HasOverlappedIoCompleted ненадежно работает поэтому:
                                Цитата
                                Do not call this macro unless the call to GetLastError returns ERROR_IO_PENDING, indicating that the overlapped I/O has started.

                                Особенно для этого случая:
                                Цитата
                                - внутренняя серверная логика приняла решение что клиент должен быть дисконнектнут
                                Сообщение отредактировано: Oleg2004 -
                                  Цитата Pacific @
                                  progman
                                  HasOverlappedIoCompleted вообще не необходимости использовать. GetQueuedCompletionStatus в любом случае вернет результат операции, либо когда она сама завершится, либо будет отменена из-за closesocket. Кстати, у тебя на один объект только один OVERLAPPED буфер ("объект унаследованный от OVERLAPPED")? Тогда тебе категорически нельзя вызывать любые overlapped операции с объектом, если текущая не завершилась. Может в этом проблема?


                                  скорее всего в этом - но я не знаю как узнать завершена она или нет.
                                  Вот у меня есть поток в который приходит команда - объект номер 1234 нужно убить.

                                  Как мне дальше правильно поступить?

                                  Добавлено
                                  Цитата Oleg2004 @
                                  Цитата progman @
                                  чем это будет отличаться от проверки HasOverlappedIoCompleted которая у меня есть и которая не надежно работает ?

                                  Возможно HasOverlappedIoCompleted ненадежно работает поэтому:
                                  Цитата
                                  Do not call this macro unless the call to GetLastError returns ERROR_IO_PENDING, indicating that the overlapped I/O has started.

                                  да. но как мне гарантированно знать что закрывать сокет можно и объект можно убивать?
                                  чтобы не произошел при этом вызов GetQueuedCompletionStatus

                                  от этого все мои проблемы (
                                    progman, я привольно понимаю, что у тебя сейчас HasOverlappedIoCompleted может бесконечно вызываться ДО closesocket?
                                      Цитата progman @
                                      Вот у меня есть поток в который приходит команда - объект номер 1234 нужно убить.

                                      Что за объект - поточнее:
                                      1. Это одиночная оверлапнутая структура?
                                      2. Это буфер нескольких таких структур?
                                      3. ???варианты...
                                      Определив что за объект, однозначно четко распознать статус самого объекта или что с ним еще может быть связано.
                                      После этого что приемлемо по статусу - убивать...
                                      Где-то так...мож что не въехал... :huh:
                                      Сообщение отредактировано: Oleg2004 -
                                        Цитата Oleg2004 @
                                        Do not call this macro unless the call to GetLastError returns ERROR_IO_PENDING, indicating that the overlapped I/O has started.

                                        Ну если хотя бы 1 одна операция с этой структурой overlapped была инициализирована до этого, то этот макрос должен работать нормально. Но я вообще никогда не видел в коде IOCP ее использования. И согласен с Pacific, что можно достаточно следить только за GetQueuedCompletionStatus.
                                          Цитата progman @
                                          Вот у меня есть поток в который приходит команда - объект номер 1234 нужно убить.

                                          Как мне дальше правильно поступить?

                                          Ну как - помечаешь на удаление, вызываешь closesocket, потом (возможно в другом потоке) GetQueuedCompletionStatus вернет ошибку для текущей overlapped операции, обработчик ошибки увидит, что для этого объекта уже вызван closesocket и он помечен на удаление, и удалит его.

                                          P.S. А разве GetQueuedCompletionStatus у тебя вызываются не из выделенных под это воркеров, а из рабочего потока? Тогда это просто плохая архитектура. Под GetQueuedCompletionStatus нужно обязательно отдельные потоки, т.к. он может вернуть управление через произвольное время.
                                          Сообщение отредактировано: Pacific -
                                            Цитата progman @
                                            Как мне дальше правильно поступить?

                                            А что за нужда убивать объект в отдельном потоке?

                                            Добавлено
                                            Цитата Pacific @
                                            т.к. он может вернуть управление через произвольное время.

                                            Кстати да, я этот момент упустил.
                                            Сообщение отредактировано: shm -
                                              Цитата shm @
                                              Ну если хотя бы 1 одна операция с этой структурой overlapped была инициализирована до этого, то этот макрос должен работать нормально. Но я вообще никогда не видел в коде IOCP ее использования.

                                              Она применяется в основном только для целей синхронизации
                                              Цитата
                                              Synchronization Macros

                                              The following macros are used with synchronization:
                                              HasOverlappedIoCompleted
                                              MemoryBarrier
                                              PreFetchCacheLine
                                              YieldProcessor


                                              Цитата
                                              И согласен с Pacific, что можно достаточно следить только за GetQueuedCompletionStatus.

                                              Я тоже к этому склоняюсь :)
                                                Цитата Oleg2004 @
                                                Цитата progman @
                                                Вот у меня есть поток в который приходит команда - объект номер 1234 нужно убить.

                                                Что за объект - поточнее:
                                                1. Это одиночная оверлапнутая структура?
                                                2. Это буфер нескольких таких структур?
                                                3. ???варианты...
                                                Определив что за объект, однозначно четко распознать статус самого объекта или что с ним еще может быть связано.
                                                После этого что приемлемо по статусу - убивать...
                                                Где-то так...мож что не въехал... :huh:

                                                под каждого законенктившегося клиента создается объект
                                                ExpandedWrap disabled
                                                  class ovpConnection: public OVERLAPPED

                                                каждый объект заносится в список
                                                создается N рабочих потоков в которых вызывается GetQueuedCompletionStatus и обрабатываются события.

                                                проблема в том что у меня не корректно удаляются эти самые объекты.
                                                основная проблема: из другого сервера приходит запрос на удаление объекта 1234
                                                В данный момент этот 1234 может из порта что то читать или что то писать или вообще заниматься обработкой своих внутренних данных

                                                Этот объект я заношу в очередь ожидания на удаление.
                                                В отдельном потоке эта очередь обрабатывается.
                                                и объекты удаляются

                                                дальше две ситуации:
                                                1. я НЕ использую макрос HasOverlappedIoCompleted и ореинтируюсь исключительно на критические секции. При этом после закрытия сокета и удаления объекта 1234 в рабочем потоке может произойти вызов GetQueuedCompletionStatus а может и не произойти - я закономерность не понимаю Она по разному себя ведет.
                                                GetQueuedCompletionStatus выдаст в поле *lpOverlapped только что удаленный объект. "только что" понятие тут растяжимое может вызваться через миллисекунду а может через 3 секунды ( у меня рекорд 5 секунд был )
                                                То что объект удален я определить уже никак не могу в этот момент - и мы падаем.

                                                2. В потоке который обрабатывает очередь объектов на удаление я у каждого объекта уточняю статус с помощью макроса HasOverlappedIoCompleted и удаляю только те у кого нет в обработке операций
                                                Падений нет но куча объектов никогда не удаляются и очередь растет.
                                                Сообщение отредактировано: progman -
                                                  Цитата progman @
                                                  под каждого законенктившегося клиента создается объект

                                                  Честно говоря, я не понимаю внутренней причины для создания такого объекта. :no-sad: Может быть доцент был тупой :D , но в сокетных операциях оверлапедная структура указывается только в конкретных вызовах send/recv, причем для каждого конкретного вызова отдельная своя структура.
                                                  Цитата progman @
                                                  я закономерность не понимаю Она по разному себя ведет.
                                                  GetQueuedCompletionStatus выдаст в поле *lpOverlapped только что удаленный объект. "только что" понятие тут растяжимое может вызваться через миллисекунду а может через 3 секунды ( у меня рекорд 5 секунд был )

                                                  Ну вот надыбал что то со временными задержками (Микрософт пишет):
                                                  Цитата
                                                  Проблема
                                                  После асинхронного ввода-вывода на жесткий диск, HasOverlappedIoCompleted возвращает TRUE, а также GetOverlappedResult() возвращает 0 байт, переданных проблемы приложения (например, Microsoft SQL Server).

                                                  Примечание: После нескольких микросекунды, GetOverlappedResult() возвращает правильное значение.
                                                  Причина
                                                  В первую очередь эта проблема наблюдалась на компьютерах, симметричная многопроцессорная обработка (SMP), где завершения ввода/вывода обновляет поля в структуре OVERLAPPED в неверном порядке.

                                                  Цитата progman @
                                                  Падений нет но куча объектов никогда не удаляются и очередь растет.

                                                  Объекты на мой взгляд какие-то левые <_< потому и ведут себя криво
                                                  Сообщение отредактировано: Oleg2004 -
                                                    Цитата progman @
                                                    в рабочем потоке может произойти вызов GetQueuedCompletionStatus а может и не произойти - я закономерность не понимаю Она по разному себя ведет.

                                                    А есть гарантия, что на момент закрвтия сокета есть активные операции ввода-вывода?
                                                    Тут мне видится 2 ситуации:
                                                    1. Операций нет и все можно сделать прямо на месте.
                                                    2. Есть операции, объект надо пометить, сокет закрыть и ждать когда завершится последняя операция.
                                                    Тут только с синхронизацией надо аккуратно.
                                                      Цитата shm @
                                                      Цитата progman @
                                                      в рабочем потоке может произойти вызов GetQueuedCompletionStatus а может и не произойти - я закономерность не понимаю Она по разному себя ведет.

                                                      А есть гарантия, что на момент закрвтия сокета есть активные операции ввода-вывода?
                                                      Тут мне видится 2 ситуации:
                                                      1. Операций нет и все можно сделать прямо на месте.
                                                      2. Есть операции, объект надо пометить, сокет закрыть и ждать когда завершится последняя операция.
                                                      Тут только с синхронизацией надо аккуратно.

                                                      все замечательно - но как я узнаю что операция есть? и как я узнаю что она закончена?
                                                        Цитата progman @
                                                        все замечательно - но как я узнаю что операция есть?

                                                        Ты можешь для отладки сделать счетчики, как Pacific советует?
                                                        Цитата progman @
                                                        и как я узнаю что она закончена?

                                                        Если пришло по ней событие - значит закончена, счетчик уменьшился на 1.
                                                          Цитата shm @
                                                          Цитата progman @
                                                          все замечательно - но как я узнаю что операция есть?

                                                          Ты можешь для отладки сделать счетчики, как Pacific советует?
                                                          Цитата progman @
                                                          и как я узнаю что она закончена?

                                                          Если пришло по ней событие - значит закончена, счетчик уменьшился на 1.

                                                          Надо попробовать но есть скептицизм
                                                          щас займусь - как будет результат я отпишусь
                                                            Тут есть есть нехорошие моменты с синхронизацией:
                                                            поток 1 установил флаг удаления объекта и закрыл сокет
                                                            произошло переключения контекста на поток 2
                                                            поток 2 уменьшил значения счетчика и он стал 0. флаг удаления установлен, поэтому объект удаляется
                                                            произошло переключение контекста на поток 1
                                                            поток 1 пытается проверить значения счетчика у уже разрушенного объекта со всеми вытекающими.
                                                            Сообщение отредактировано: Oleg2004 -
                                                              Цитата progman @
                                                              При этом после закрытия сокета и удаления объекта 1234 в рабочем потоке может произойти вызов GetQueuedCompletionStatus а может и не произойти - я закономерность не понимаю Она по разному себя ведет.

                                                              Вот обратил внимание на эту фишку - как это понять - может произойти, а может и нет?
                                                              Есть код, где прописан вызов GetQueuedCompletionStatus - и в этом месте он должен произойти...как иначе то???
                                                              Или есть условие - в одном случае - вызываем, в другом - нет. но ведь и это детерминировано...
                                                              Или поток сконструирован так - что гуляет по коду как хочет? :wacko:
                                                              Чето я архитектуру приложения недопонимаю...
                                                              PS
                                                              А можно кусочек кода с этими объектами
                                                              class ovpConnection: public OVERLAPPED
                                                              - где хранятся, как место хранения описано, как доступ к этому месту и откуда он возможен и прочее...чуть чуть...
                                                              А вообще у меня большое недоверие - можно ли эту уникальную структуру объявлять в виде класса, да еще и паблик. :( Пару полей в ней уникальны и используются только ядром...потому и проблемы бывают, как я выше писал.
                                                              Сообщение отредактировано: Oleg2004 -
                                                                Цитата Oleg2004 @
                                                                Цитата progman @
                                                                При этом после закрытия сокета и удаления объекта 1234 в рабочем потоке может произойти вызов GetQueuedCompletionStatus а может и не произойти - я закономерность не понимаю Она по разному себя ведет.

                                                                Вот обратил внимание на эту фишку - как это понять - может произойти, а может и нет?
                                                                Есть код, где прописан вызов GetQueuedCompletionStatus - и в этом месте он должен произойти...как иначе то???
                                                                Или есть условие - в одном случае - вызываем, в другом - нет. но ведь и это детерминировано...
                                                                Или поток сконструирован так - что гуляет по коду как хочет? :wacko:
                                                                Чето я архитектуру приложения недопонимаю...
                                                                PS
                                                                А можно кусочек кода с этими объектами
                                                                class ovpConnection: public OVERLAPPED
                                                                - где хранятся, как место хранения описано, как доступ к этому месту и откуда он возможен и прочее...чуть чуть...
                                                                А вообще у меня большое недоверие - можно ли эту уникальную структуру объявлять в виде класса, да еще и паблик. :( Пару полей в ней уникальны и используются только ядром...потому и проблемы бывают, как я выше писал.

                                                                А я не знаю.
                                                                на стороне сервера закрытие клиентского сокета может привести к срабатыванию вызова GetQueuedCompletionStatus в рабочем потоке а может нет
                                                                если вызов произошел то GetQueuedCompletionStatus может вернуть FALSE и как валидный ( еще не удаленный ) указатель на OVERLAPPED так и вернуть удаленный пару секунд назад объект OVERLAPPED
                                                                А может вернуть TRUE но кол-во байт 0 прочитанных в lpNumberOfBytes и аналогично или валидный указатель на OVERLAPPED или указательна только что удаленный объект.

                                                                вот такая херь у меня. и как разгребать я хз.

                                                                Добавлено
                                                                Цитата shm @
                                                                Цитата progman @
                                                                все замечательно - но как я узнаю что операция есть?

                                                                Ты можешь для отладки сделать счетчики, как Pacific советует?
                                                                Цитата progman @
                                                                и как я узнаю что она закончена?

                                                                Если пришло по ней событие - значит закончена, счетчик уменьшился на 1.

                                                                Получается что почти все время жизни объекта счетчик операций в 1 стоит.
                                                                Потому как после успешного завершения чтения или посылки данных объект вызывает чтение данных с порта и ждет когда они придут.
                                                                  Цитата progman @
                                                                  А я не знаю.
                                                                  на стороне сервера закрытие клиентского сокета может привести к срабатыванию вызова GetQueuedCompletionStatus в рабочем потоке а может нет

                                                                  :wall: :wall: :wall:
                                                                  Вот этого я никак не могу понять.
                                                                  Что вы понимаете под НЕсрабатыванием вызова GetQueuedCompletionStatus? :blink:
                                                                  Решил почитать свой конспект лекций:
                                                                  Цитата
                                                                  Каждая завершившаяся тем или иным образом операция ввода/вывода, назначенная на данный порт завершения, сообщает о своем возврате с помощью специального системного пакета, который поступает в очередь завершенных запросов порта. Для обработки этой очереди и предназначены наши рабочие потоки. Достигается это с использованием функции GetQueuedCompletionStatus(), которая пытается извлечь из очереди пакет завершения соответствующей операции

                                                                  Таким образом, другого способа определения статуса операции ввода/вывода просто нет.
                                                                  Эту функцию мы просто обязаны вызывать.
                                                                  Как же можно говорить о несрабатывании ВЫЗОВА?????? :wall: :'(

                                                                  Цитата progman @
                                                                  если вызов произошел то GetQueuedCompletionStatus может вернуть FALSE и как валидный ( еще не удаленный ) указатель на OVERLAPPED так и вернуть удаленный пару секунд назад объект OVERLAPPED
                                                                  А может вернуть TRUE но кол-во байт 0 прочитанных в lpNumberOfBytes и аналогично или валидный указатель на OVERLAPPED или указатель на только что удаленный объект.
                                                                  вот такая херь у меня. и как разгребать я хз.

                                                                  Почитал у себя еще:
                                                                  Цитата
                                                                  При корректном завершении работы порта завершения главное - не освобождать память со структурой OVERLAPPED, пока выполняется какая-нибудь операция на сокете. Так же надо знать, что закрытие сокета с помощью closesocket() прерывает любые продолжающиеся операции на данном порту завершения.

                                                                  И еще
                                                                  Цитата
                                                                  Пусть в нашу систему прибыло 100 байтов, в результате возникло событие FD_READ. За этими данными пришел сегмент с уведомлением о закрытии соединения на той стороне. В стек сетевых событий этого сокета добавился FD_CLOSE. Мы считываем 30 байтов – остается непрочитанными 70 байтов, потому снова возникает событие FD_READ. В стеке теперь расположены FD_CLOSE, за которым следует FD_READ. Если мы теперь обработаем FD_CLOSE и закроем сокет, мы потеряем оставшиеся в буфере приема данные. О чем это говорит? Полагаться на сетевое событие здесь не совсем логично – надо полагаться только на возврат функцией recv() значения 0.

                                                                  В вашем случае это будет скорее всего lpNumberOfBytesTransferred=0

                                                                  В общем если это ваш собственный сервер, то надо менять архитектуру и использовать структуру
                                                                  ExpandedWrap disabled
                                                                    typedef struct {
                                                                        OVERLAPPED Overlapped;
                                                                        //любые полезные нам данные:
                                                                        WSABUF DataBuf;
                                                                        CHAR Buffer[DATA_BUFSIZE];
                                                                        DWORD BytesSend;
                                                                        DWORD BytesRecv;
                                                                        DWORD OperationType;
                                                                        DWORD TotalBytes;
                                                                        .....
                                                                    } PER_IO_OPERATION_DATA;

                                                                  КУда в //любые полезные нам данные: и можно будет вставить признаки всякие или счетчики.
                                                                  Это есть в примере у меня в конспекте как это делать.
                                                                    Цитата Oleg2004 @
                                                                    Вот этого я никак не могу понять.
                                                                    Что вы понимаете под НЕсрабатыванием вызова GetQueuedCompletionStatus?

                                                                    Мне на ум пришел только один вариант - когда клиент отваливается так, что даже RST пакет не доходит до сервера, и сервер думает, что клиент все еще подключен. Но таких клиентов сервер сам должен отбрасывать по таймауту - либо getsockopt(socket, SOL_SOCKET, SO_CONNECT_TIME, ...), если соединение в стиле либо "вкл-запрос-ответ-выкл", либо вручную отслеживать, когда пришел последний пакет.
                                                                    Сообщение отредактировано: Pacific -
                                                                      Цитата Pacific @
                                                                      Мне на ум пришел только один вариант - когда клиент отваливается так, что даже RST пакет не доходит до сервера, и сервер думает, что клиент все еще подключен. Но таких клиентов сервер сам должен отбрасывать по таймауту - либо getsockopt(socket, SOL_SOCKET, SO_CONNECT_TIME, ...), если соединение в стиле либо "вкл-запрос-ответ-выкл", либо вручную отслеживать, когда пришел последний пакет.

                                                                      Ну, прямо скажем - это единственный вариант, когда сервер ждет данных (любых, как и FIN-cегмента или RST) - слишком долго. Как долго он может ждать? До 2-х часов - это стандарт TCP.
                                                                      Если рассматривать такую ситуацию с несрабатыванием - то вы правы. И способов грамотной организации таймаутов такого рода - достаточно много - это и проверка пульса с помощью срочных данных, и select(), и таймаут WSAWaitForMultipleEvents() и простой даже sleep().
                                                                      Что то я думаю в архитектуре все-таки не то...
                                                                      Но ведь автор пишет:
                                                                      Цитата progman @
                                                                      объекты уходят на удаление в двух случаях:
                                                                      - GetQueuedCompletionStatus вернул FALSE или *lpNumberOfBytes вернулось ноль
                                                                      - внутренняя серверная логика приняла решение что клиент должен быть дисконнектнут

                                                                      Значит у этой внутренней логики какой-то есть внутренний критерий?
                                                                      И если он срабатывает, то очевидно что вызов GetQueuedCompletionStatus() в этом случае в принципе может быть лишним...
                                                                      Сообщение отредактировано: Oleg2004 -
                                                                        Цитата Oleg2004 @
                                                                        Что вы понимаете под НЕсрабатыванием вызова GetQueuedCompletionStatus?

                                                                        Какое то недопонимание или я конкретно туплю.
                                                                        Есть у меня 16 потоков и там крутится GetQueuedCompletionStatus и там происходит прием/передача и обработка пакетов
                                                                        Есть еще два потока: номер 17 удаляющий и номер 18, который слушающий сервер управления.

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

                                                                        Понимаете? Я закрываю в потоке 17 сокет и удаляю OVERLAPPED структуру а она херакс и через некоторое время высплывает в обработчике в GetQueuedCompletionStatus
                                                                        Я не знаю как гарантированно и безопасно удалить OVERLAPPED структуру чтобы она на 146% не была возвращена как результат работы функции GetQueuedCompletionStatus в одном из рабочих потоков 1-16 после ее удаления
                                                                        :wall: :wall: :wall: :wall: :wall: :wall:
                                                                        Сообщение отредактировано: progman -
                                                                          Сделал грязный хак - когда происходит занесение объекта в лист на удаление я закрываю сокет объекта и добавил 20 секундный таймер ожидания.
                                                                          Через 20 секунд объект удаляется.
                                                                            Цитата progman @
                                                                            Я закрываю в потоке 17 сокет и удаляю OVERLAPPED структуру а она херакс и через некоторое время высплывает в обработчике в GetQueuedCompletionStatus

                                                                            Так мы про что талдычим уже 3 страницы? Нельзя просто взять и удалить OVERLAPPED структуру, пока она используется системой. Надо ждать возврата ее из GetQueuedCompletionStatus, потом только удалять.
                                                                              Цитата Pacific @
                                                                              Нельзя просто взять и удалить OVERLAPPED структуру, пока она используется системой. Надо ждать возврата ее из GetQueuedCompletionStatus, потом только удалять.

                                                                              Именно так и есть.
                                                                              Если в некотором потоке закрывается сокет с помощью closesoket(), в очередь системных пакетов порта завершения ставится пакет, посылающий FIN клиенту. Каким по очереди он будет - сие науке неизвестно, и когда завершится - тем более. Система переключает на другие потоки, они роются в этой очереди, обрабатывают другие пакеты, и когда-то потом система доберется до сегмента FIN. Именно поэтому GetQueuedCompletionStatus срабатывает и возвращает значение какое уж там получится - то TRUE то FALSE. Ведь до отсылки пакета дело могло еще и не дойти - потоков то много, они все переключаются.
                                                                              Отсюда и этот разброс по времени:
                                                                              Цитата
                                                                              GetQueuedCompletionStatus выдаст в поле *lpOverlapped только что удаленный объект. "только что" понятие тут растяжимое может вызваться через миллисекунду а может через 3 секунды ( у меня рекорд 5 секунд был )

                                                                              Именно поэтому надо дожидаться реального возврата GetQueuedCompletionStatus и только после этого удалять все что ассоциировано программой с закрытым сокетом.
                                                                              Именно поэтому то и срабатывает идея со слипом, о которой я писал раньше.
                                                                              PS
                                                                              Вообще то мелкомягкие ступили. Если сокет был создан для режима перекрытия, для которого обязательна оверлапная структура, то можно было поставить флаг автоматического или ручного ее освобождения при закрытии сокета. Это решило бы проблему. Скажем в нашем случае это должно быть ручное.
                                                                              Еще одно замечание...
                                                                              Сокет ассоциируется с портом...а вот отсоединения использованного сокета - увы...Опять мелкомягкие не додумали...
                                                                              Сообщение отредактировано: Oleg2004 -
                                                                                Цитата Pacific @
                                                                                Цитата progman @
                                                                                Я закрываю в потоке 17 сокет и удаляю OVERLAPPED структуру а она херакс и через некоторое время высплывает в обработчике в GetQueuedCompletionStatus

                                                                                Так мы про что талдычим уже 3 страницы? Нельзя просто взять и удалить OVERLAPPED структуру, пока она используется системой. Надо ждать возврата ее из GetQueuedCompletionStatus, потом только удалять.

                                                                                А я о чем талдычу? Я понятия не имею используется она сейчас или нет ( да это архитектурный просчет ).
                                                                                Более того закрытие сокета как показали опыты не всегда ведет к вызову GetQueuedCompletionStatus в одном из рабочих потоков! Вот так. Я сокет закрыл а в GetQueuedCompletionStatus тишина, 5 секунд, 10 секунд, 20 секунд...
                                                                                Я структуру удалил и секунд через 30 произошел вызов GetQueuedCompletionStatus а может и не произойти и все происходит нормально.
                                                                                Я не нашел никакой зависимости.

                                                                                Сейчас онлайн 7 тысяч постоянный. Раз в сутки описанная ситуация срабатывает и сервер падает.
                                                                                То есть я закрываю сокет и жду 20 секунд перед тем как удалить структуру. И раз в 24 часа 20 секундного ожидания оказывается недостаточно!

                                                                                PS CancelIoEx проблемы не решает ((( от нее не тепло не холодно

                                                                                Добавлено
                                                                                Цитата Oleg2004 @
                                                                                Именно поэтому надо дожидаться реального возврата GetQueuedCompletionStatus и только после этого удалять все что ассоциировано программой с закрытым сокетом.

                                                                                у меня был опыт из одного тестового клиента подключенного к серверу.
                                                                                сокет клиента был закрыт по инициативе сервера. GetQueuedCompletionStatus не вызвалась вообще.
                                                                                Ждал около часа. Keep-alive на 5 секунд сокету был назначен.
                                                                                Клиент физически был закрыт на клиентской машине и машине был сделан резет.
                                                                                все равно - тишина в GetQueuedCompletionStatus

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

                                                                                PS если делать как вы мне тут советуете и удалять объекты ТОЛЬКО после вызова GetQueuedCompletionStatus то копится оч большая утечка памяти потому что для оч большого кол-ва соединений срабатывание не происходит
                                                                                Сообщение отредактировано: progman -
                                                                                  Цитата progman @
                                                                                  да. но как мне гарантированно знать что закрывать сокет можно и объект можно убивать?
                                                                                  чтобы не произошел при этом вызов GetQueuedCompletionStatus


                                                                                  Добавь CRITICAL_SECTION
                                                                                    Цитата ter_nk_ @
                                                                                    Цитата progman @
                                                                                    да. но как мне гарантированно знать что закрывать сокет можно и объект можно убивать?
                                                                                    чтобы не произошел при этом вызов GetQueuedCompletionStatus


                                                                                    Добавь CRITICAL_SECTION

                                                                                    :D
                                                                                    куда??? в рабочий поток? и парализовать работу всего сервера?
                                                                                      Нашел кое-что почти по вашей теме.
                                                                                      Там тоже говорят о задержке - аж до 4 минут, но shutdown()вроде помог.
                                                                                      Т.е. о чем я думаю.
                                                                                      GetQueuedCompletionStatus() напрямую предназначена для отслеживания операций ввода-вывода - т.е. типа recv() и send().
                                                                                      Операция closesocket - тоже вроде бы I/O, да специфическая. В ней приложение и сокетные буфера в модуле TCP не используются - closesocket только лишь приказ модулю TCP послать служебный сегмент с флагом FIN. Видимо в ядре формирование системных пакетов порта завершения, относящихся к закрытию сокета, микрософт сделала криво. Отсюда и проблемы.
                                                                                      Ну и конечно же не соответствие вашей архитектуры рекомендациям:
                                                                                      Цитата
                                                                                      Обычно рекомендуется, чтобы функция CreateIoCompletionPort() задавала один поток для каждого отдельного процессора во избежание переключения контекста потока.

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

                                                                                      Добавлено
                                                                                      Ну и еще вдогонку - что на самом деле представляет собой вызов GetQueuedCompletionStatus()
                                                                                      Цитата
                                                                                      После завершения асинхронной операции ввода/вывода для ассоциированного файла диспетчер ввода/вывода создает пакет запроса из структуры OVERLAPPED и ключа завершения и помещает его в очередь с помощью вызова KeInsertQueue(). Когда поток вызывает функцию GetQueuedCompletionStatus(), на самом деле вызывается функция NtRemoveIoCompletion(). NtRemoveIoCompletion() проверяет параметры и вызывает функцию KeRemoveQueue(), которая блокирует поток, если в очереди отсутствуют запросы, или поле CurrentCount структуры KQUEUE больше или равно MaximumCount. Если запросы есть, и число активных потоков меньше максимального, KeRemoveQueue() удаляет вызвавший ее поток из очереди ожидающих потоков и увеличивает число активных потоков на 1. При занесении потока в очередь ожидающих потоков поле Queue структуры KTHREAD устанавливается равным адресу порта завершения. Когда запрос помещается в порт завершения функцией PostQueuedCompletionStatus(), на самом деле вызывается функция NtSetIoCompletion(), которая после проверки параметров и преобразования хендла порта в указатель вызывает KeInsertQueue().

                                                                                      Куча вызовов, и не дай Бог закончится квант времени с последующим переключением контекста...мало не покажется.
                                                                                      Сообщение отредактировано: Oleg2004 -
                                                                                        Цитата Oleg2004 @
                                                                                        Ну и конечно же не соответствие вашей архитектуры рекомендациям:

                                                                                        Я в другой литературе встречал рекомендацию 2 рабочих потока на ядро.
                                                                                        У меня в сервере Intel® Xeon® E5-1650 v3 Hexa-Core Haswell - всего 12 рабочих потоков с GetQueuedCompletionStatus крутится
                                                                                        Плюс три служебных потока с мониторингаоми дополнительных служб.

                                                                                        Цитата Oleg2004 @
                                                                                        но shutdown()вроде помог.

                                                                                        спасибо - попробую
                                                                                        Сообщение отредактировано: progman -
                                                                                          Посмотрел спецификацию Intel® Xeon® E5-1650 v3 Hexa-Core Haswel - это однопроцессорная 6-ти ядерная платформа.
                                                                                          Неплохо, но это все равно один процессор. :)

                                                                                          Цитата progman @
                                                                                          Я в другой литературе встречал рекомендацию 2 рабочих потока на ядро.

                                                                                          Ссылочку не дадите?
                                                                                          Но, как мне кажется, переключений контекстов даже в вашей конфигурации не избежать.
                                                                                          И конечно же совершенно недопустимо чтобы сервер падал. Это самая большая неприятность, остальное как бы можно пережить, а вот падение...
                                                                                          Решений наверно много. Можно ведь и не самописный сервер использовать, а пробовать коммерческую версию, если деньги есть.
                                                                                          Или поднять еще один сервер и балансировать нагрузку.
                                                                                          Можно и попробовать продумать какую-то новую архитектуру серверного проекта...
                                                                                          И тд...
                                                                                            2 рабочих потока на ядро нужно, чтобы если один из них на чем-то застрянет (файловые операции, обращение к базе данных и т.д.), то второй сможет дальше обрабатывать запросы. И не 2 потока на ядро, а N*2 потоков на N ядер, не привязанных к конкретным ядрам. Механизм IOCP все равно поставит ограничение в максимум N активных потоков (по умолчанию).
                                                                                              Цитата progman @
                                                                                              Понимаете? Я закрываю в потоке 17 сокет и удаляю OVERLAPPED структуру а она херакс и через некоторое время высплывает в обработчике в GetQueuedCompletionStatus
                                                                                              Я не знаю как гарантированно и безопасно удалить OVERLAPPED структуру чтобы она на 146% не была возвращена как результат работы функции GetQueuedCompletionStatus в одном из рабочих потоков 1-16 после ее удаления

                                                                                              Один из возможных вариантов практического решения
                                                                                              проблемы буквально содержится в вопросе.
                                                                                              Для этого можно изменить структуру объектов, обслуживающих внешние запросы.
                                                                                              ---
                                                                                              1. Допустим, поместили объект в список на уничтожение.
                                                                                              2. уничтожаем всё, кроме OVERLAPPED-структуры, которую
                                                                                              засылаем в отстойный список.
                                                                                              3. Если она будет получена как результат в GetQueuedCompletionStatus,
                                                                                              то будет законно удалена.
                                                                                              4. Если нет - уничтожим её по TOUT. Только не 20 секунд, а 20 часов. Или 50..
                                                                                              Памяти структура занимает не много. Такое "подвешивание" ресурсов, вероятно, можно допустить.
                                                                                              ---
                                                                                              Исследования по правильной зачистке объектов надо продолжить.
                                                                                              Возможно, проблемы прекратятся после уничтожения порта завершения
                                                                                              и создания вместо него нового. Или существует какой-то баг, который
                                                                                              просто проявляется таким образом.
                                                                                              Сообщение отредактировано: ЫукпШ -
                                                                                                Цитата ЫукпШ @
                                                                                                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 Кбайт, скачиваний: 172)
                                                                                                      Файлик малость подправил - даже оригинал в дэжавю такого качества что порой не разберешь.
                                                                                                      Самое главное, что здесь Рихтер рассказал - это поведение рабочих потоков, выполняющих
                                                                                                      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 просто закрываю порт. Буст видимо внутри сам все разруливает как то - но деструктор коннектора вызывается практически мгновенно.
                                                                                                                              Цитата 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 -
                                                                                                                                                            Цитата shm @
                                                                                                                                                            Цитата ЫукпШ @
                                                                                                                                                            Делаем приблизительно так:

                                                                                                                                                            Велосипед с квадратными колесами.

                                                                                                                                                            Очень может быть.
                                                                                                                                                            Но существует случай, когда скромный велосипед лучше
                                                                                                                                                            модного "мерседеса".
                                                                                                                                                            Это когда мерседес постоянно валяется в кювете.
                                                                                                                                                            ---
                                                                                                                                                            Кроме того, можно заметить, что порт завершения для этой задачи не так уж и нужен.
                                                                                                                                                            Поскольку он позволяет следить за разнородными объектами, а в данном
                                                                                                                                                            случае требуется следить только за сокетами.
                                                                                                                                                            Совершенно не понятно, как разорвать ассоциацию порта и сокета, а это
                                                                                                                                                            существенный вопрос.
                                                                                                                                                            (Возможно, уничтожением порта завершения и создания нового ? Не уверен.)
                                                                                                                                                            Зато при использовании сокетов беркли "разрыв ассоциации"
                                                                                                                                                            не проблема. В результате легко и просто организовать "конвейерную" обработку
                                                                                                                                                            клиентов. Без любых проблем в многопоточной манипуляции сокетами.
                                                                                                                                                            При этом сам "сервер" даже может (а, наверное, и должен) не знать,
                                                                                                                                                            что он "сетевой". Он просто манипулирует объектами-клиентами.
                                                                                                                                                            Сообщение отредактировано: ЫукпШ -
                                                                                                                                                              Цитата Oleg2004 @
                                                                                                                                                              Ясно что система работает практически на грани возможностей IOCP.

                                                                                                                                                              В искуственных тестах нагрузки она у меня и 50 тысяч в минуту держала на одном сервере.
                                                                                                                                                              Давайте считать: 10 мс время обработки одного пакета - значит один поток обработает за секунду 100 пакетов или 6000 за минуту.
                                                                                                                                                              У меня 16 потоков. В минуту будет 96000
                                                                                                                                                              даже если ошабаюсь на 50 процентов я то 40 тысяч в минуту держать должен

                                                                                                                                                              так что до потолка ой как далеко.
                                                                                                                                                              Если отключить запись в БД или очень сильно озадачиться оптимизацией этой записи - напрмиер ее вести асинхронно то время на обработку одного потока падает до 0-1мс
                                                                                                                                                                Цитата Oleg2004 @
                                                                                                                                                                Ясно что система работает практически на грани возможностей IOCP.

                                                                                                                                                                Когда я тестировал грани возможностей IOCP, у меня 6-ядерный сервер держал 30000 запросов в секунду. И выдержал бы больше, если бы это был простой echo-сервер.
                                                                                                                                                                  Ну что ж, progman,Pacific - вы меня убедили и я даже за мелкомягкое изобретение IOCP имею немного гордости... :D молодцы, все таки что то стоящее сочинили.
                                                                                                                                                                  Значит и надо его юзать по полной, а проблемы решать по мере поступления.
                                                                                                                                                                  Ну а теперь по расчетам.
                                                                                                                                                                  Цитата progman @
                                                                                                                                                                  Давайте считать: 10 мс время обработки одного пакета - значит один поток обработает за секунду 100 пакетов или 6000 за минуту.

                                                                                                                                                                  Этот расчет слишком на мой взгляд слишком арифметически прямолинеен.
                                                                                                                                                                  В любой сложной системе крутятся сотни процессов и может быть тысячи потоков. Время переключения контекста потока с одного на другой в разных процессорных системах может колебаться от 20 до 300 циклов - смотрел только что в гуглях. Кроме того, надо учитывать и приоритетность и прочая. Так что процентов на 10-15 я бы ваши цифры уменьшил бы... :)
                                                                                                                                                                  Цитата Pacific @
                                                                                                                                                                  Когда я тестировал грани возможностей IOCP, у меня 6-ядерный сервер держал 30000 запросов

                                                                                                                                                                  А сколько было рабочих потоков?
                                                                                                                                                                  Ну и кстати такой вопрос - а что такое "запрос"???
                                                                                                                                                                  Это понятие ой как растяжимое. Скажем HTTP-запрос на сервер GET вообще может содержать не более чем 256 символов - а ответ на него может длиться секундами - пересылка сотен картинок и страниц текста. Так что обработка запроса должна рассматриваться только после ответа.
                                                                                                                                                                  Если просто принимать запросы - и не отвечать на них - тогда другое дело. Т.е. цифры зависят от характера транзакций.
                                                                                                                                                                  Цитата Pacific @
                                                                                                                                                                  И выдержал бы больше, если бы это был простой echo-сервер.

                                                                                                                                                                  У эхо-сервера нет процесса обработки запроса.
                                                                                                                                                                  Если туда Хелло и обратно Хелло - может быть.
                                                                                                                                                                  А к примеру, в качестве запроса на эхо я шлю файлик так под мегабайт. И буду ждать ответа сервера. Тоже выдержит?
                                                                                                                                                                  Не все так просто...
                                                                                                                                                                  Но все равно, опыт ваш и прогмана впечатляет.
                                                                                                                                                                  Только вот прогман сдал IOCP и променял его на буст-обертку... :'(
                                                                                                                                                                  Кстати, где-то в сети встречал сравнение по скорости исполнения одного и того же
                                                                                                                                                                  достаточно емкого запроса. Буст явно проигрывал...потому как библиотека, а не родное АПИ.
                                                                                                                                                                  Сообщение отредактировано: Oleg2004 -
                                                                                                                                                                    Цитата Oleg2004 @
                                                                                                                                                                    Ну и кстати такой вопрос - а что такое "запрос"???

                                                                                                                                                                    Там был свой протокол на базе TCP+SSL. От клиента приходит не больше 1 Кб, от сервера к клиенту - от 1 до 64 Кб (в среднем было 3-4 Кб). Вот это все (установка TCP соединения, SSL хэндшейк, обработка запроса и закрытие соединения) обрабатывалось по 30000 в секунду. Все это конечно тестировалось в гигабитной локалке, в реальной работе таких нагрузок не было.
                                                                                                                                                                      Цитата Pacific @
                                                                                                                                                                      Все это конечно тестировалось в гигабитной локалке, в реальной работе таких нагрузок не было.

                                                                                                                                                                      Это реально впечатляет. Вот что IOCP творить может :D
                                                                                                                                                                        Цитата Oleg2004 @
                                                                                                                                                                        Этот расчет слишком на мой взгляд слишком арифметически прямолинеен.
                                                                                                                                                                        В любой сложной системе крутятся сотни процессов и может быть тысячи потоков. Время переключения контекста потока с одного на другой в разных процессорных системах может колебаться от 20 до 300 циклов - смотрел только что в гуглях. Кроме того, надо учитывать и приоритетность и прочая. Так что процентов на 10-15 я бы ваши цифры уменьшил бы...

                                                                                                                                                                        В данный момент как я уже писал у меня 16 потоков и примерно 7000 в минуту запросов обрабатывается.
                                                                                                                                                                        Счетчик показывает что среднее время на обработку одного запроса 10мс. Причем 99% этого времени занимает запись в БД.
                                                                                                                                                                        Загрузка CPU меньше одного процента.
                                                                                                                                                                        Почему я не имею право экстраполировать? ))))
                                                                                                                                                                          Цитата progman @
                                                                                                                                                                          Почему я не имею право экстраполировать? ))))

                                                                                                                                                                          Имеете...у вас же все карты на руках... :D
                                                                                                                                                                          Я же выступаю с позиции удаленного скептика...а вы - локального прагматика. :)
                                                                                                                                                                          0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                                                                                                                                                          0 пользователей:


                                                                                                                                                                          Рейтинг@Mail.ru
                                                                                                                                                                          [ Script execution time: 0,2266 ]   [ 18 queries used ]   [ Generated: 30.03.24, 00:41 GMT ]