Принимаю в цикле данные с помощью WSARecv() в блокирующем режиме (без OVERLAPPED).
В случае, если пакеты приходят, всё нормально. Если пакетов нет, то ожидаемо возвращается SOCKET_ERROR и WSAGetLastError() возвращает WSAETIMEDOUT. Так работает почти везде.
Но на одном очень быстром сервере (128 ядер), иногда, вместо WSAETIMEDOUT возвращается WSA_IO_PENDING. Т.е. на блокирующем вызове (только по истечении таймаута) функция WSARecv возвращает, что операция не завершена и активна (потенциально). Тут я уже напрягся, т.к. OVERLAPPED создается внутри на стеке и потенциально драйвер может туда записать.
После продолжительных тестов на этом сервере опасения подтвердились: код падал в случайных местах незадолго после возврата из WSARecv.
Вопрос к знатокам, как такое поведение вообще возможно? Это баг реализации ? Если да, то на каком уровне проблема может быть?
P.S. Всё это было нужно только для того, что бы использовать таймаут на приеме пакетов по UPD и обошел я это реализацией своей блокирующей версией, которая явно использует OVERLAPPED и вызывает у него CancelIOEx() и дожидается c помощью WSAGetOverlappedResult() реального завершения операции. Вроде пока пронесло, но осадочек отрицательный остался.
Здравствуйте, Videoman, Вы писали:
V>Вопрос к знатокам, как такое поведение вообще возможно? Это баг реализации ? Если да, то на каком уровне проблема может быть?
Здравствуйте, Videoman, Вы писали:
V>В случае, если пакеты приходят, всё нормально. Если пакетов нет, то ожидаемо возвращается SOCKET_ERROR и WSAGetLastError() возвращает WSAETIMEDOUT. Так работает почти везде. V>Но на одном очень быстром сервере (128 ядер), иногда, вместо WSAETIMEDOUT возвращается WSA_IO_PENDING.
Такое ощущение, что данные пришли, начали обрабатываться, но не успели из-за наступления таймаута. Может ждать данных на сокете с помощью select? Будет или timeout или успех (данные пришли, можно читать). Вот если пришли и при чтении таймаут/pending, то, значит, реально таймаут.
Здравствуйте, Videoman, Вы писали:
V>P.S. Всё это было нужно только для того, что бы использовать таймаут на приеме пакетов по UPD и обошел я это реализацией своей блокирующей версией, которая явно использует OVERLAPPED и вызывает у него CancelIOEx() и дожидается c помощью WSAGetOverlappedResult() реального завершения операции. Вроде пока пронесло, но осадочек отрицательный остался.
Вообще, блокирующийся режим сокет — это такая, довольно бесполезная хрень. Если кто-то использует сокет в блокирующемся режиме, то или это какая-то совсем уж тривиальная програмка, или всё равно придетса какую-то многопоточность городить.
Поэтому меня не очень удивляет, что в блокирующемся режиме их хуже тестируют.
Я думаю, более-менее рабочие конфигурации — это или OVERLAPPED, или WASPoll. И с ними сюрпризов не будет (иначе вендой вообще невозможно было бы пользоваться).
Здравствуйте, Pzz, Вы писали:
Pzz>Я думаю, более-менее рабочие конфигурации — это или OVERLAPPED, или WASPoll. И с ними сюрпризов не будет (иначе вендой вообще невозможно было бы пользоваться).
Ну в итоге так и пришлось сделать. Кажется реализация при таймауте просто зовет CancelIO() и выходит не дожидаясь реального окончания операции. Зато быстро работает
Pzz>>Я думаю, более-менее рабочие конфигурации — это или OVERLAPPED, или WASPoll. И с ними сюрпризов не будет (иначе вендой вообще невозможно было бы пользоваться). V>Ну в итоге так и пришлось сделать. Кажется реализация при таймауте просто зовет CancelIO() и выходит не дожидаясь реального окончания операции. Зато быстро работает
Судя по этой фразе в документации, оно под капотом именно так и сделано, но чтото пошло не так:
If the socket is created using the WSASocket function, then the dwFlags parameter must have the WSA_FLAG_OVERLAPPED attribute set for the timeout to function properly. Otherwise the timeout never takes effect.
Как много веселых ребят, и все делают велосипед...
Здравствуйте, Videoman, Вы писали:
Pzz>>Я думаю, более-менее рабочие конфигурации — это или OVERLAPPED, или WASPoll. И с ними сюрпризов не будет (иначе вендой вообще невозможно было бы пользоваться).
V>Ну в итоге так и пришлось сделать. Кажется реализация при таймауте просто зовет CancelIO() и выходит не дожидаясь реального окончания операции. Зато быстро работает
Ну в простом случае можно не трахаться с OVERLAPPED, а обойтись WSAPoll.
Я думаю, для одного сокета WSAPoll чуть быстрее на самом деле. Но OVERLAPPED лучше массштабируется. Но это не точно, я больше по UNIX-овской части, чем по венде
Здравствуйте, ononim, Вы писали:
O>Судя по этой фразе в документации, оно под капотом именно так и сделано, но чтото пошло не так: O>
If the socket is created using the WSASocket function, then the dwFlags parameter must have the WSA_FLAG_OVERLAPPED attribute set for the timeout to function properly. Otherwise the timeout never takes effect.
Да, еще одно подтверждение. Косвенно можно догадаться, т.к. создавая сокет через socket(), не нужно указывать никакого флага, а WSARecv начинает работать с блоком или без в зависимости от указателя/его отсутствия на OVERLAPPED
Здравствуйте, Pzz, Вы писали:
Pzz>Я думаю, для одного сокета WSAPoll чуть быстрее на самом деле. Но OVERLAPPED лучше массштабируется. Но это не точно, я больше по UNIX-овской части, чем по венде
Согласен. Но мне больше нравится Completion Ports, если уж погружаться в блуд глубоко. Я как-то ставил эксперименты с ним и у меня получалось до 1 млн. быстрых вызовов прокачивать благодаря его LIFO.