Сейчаз реализован и используется сервер, в основе которого блокирующие сокеты. Т.е. данные из сети читаются в одном месте (в отдельном потоке), а отсылаются в сеть в любом месте. Каждый подключившийся клиент использует свой отдельной поток. Клиентов стало значительно больше с недавних пор. Поэтому стала задача полностью переделать сервер. Т.е. сделать сервер асинхронным, да и что бы тысячи клиентов обслуживал небольшое количество потоков (пул потоков).
За последние 2 месяца много чего прочитал и узнал нового.
Нашёл на просторах инета грамотную реализацию HTTP сервера на основе IOCP (с пулом потоков).
Вот как он реализован:
1) Принимает соединения через AcceptEx в отдельном потоке AcceptThread, предварительно создав вызвав CreateIoCompletionPort для AcceptSocket'а.
2) Поток WorkThread вызывает GetQueuedCompletionStatus и вызываются соот-щие обработчики (тип события хранится после структуры Overlapped).
3) Когда возникает событие MY_ACCEPT вызываем обработчик чтения из сокета (он же вызывется и при событии MY_READ).
4) В обработчике MY_READ читаем то что пришло из буфера и если получили не всё, то вызывам WSARecv и "ждём" события MY_READ.
5) Наконец то прочитали пакет (запрос) целиком, обработали его, вызываем WSASend (передали в параметры событие MY_WRITE).
6) "Ждём" запуска обработчика MY_WRITE (окончание слития в сеть). Вызываем снова WSARecv что бы замкнуть порочный круг ...
Т.е. эта реализация обеспечивает протокол обмена типа: acceptEx -> получили запрос -> отправили ответ -> ждём запрос...
У меня же протокол совсем не HTTP. У меня клиент может послать пакет серверу и при этом сервер не обязан на него отвечать. Да и сервер посылает клиенту команды, которые не требуют подтверждения.
Вот и не знаю как этот HTTP сервер передалать под мой протокол.
Да и не знаю как в этом сервере из любого другого потока в любой момент времени послать "моментально" данные клиенту.
Да и можно ли использовать один и тот же сокет в разных потоках "одовременно"?
Обязательно ли дожидаться окончания выполнения WSASend что бы вызвать WSARecv? И наоборот?
Ещё читал что, перекрытый ввод-вывод лучше подходит для обмена в режиме "запрос-ответ" (HTTP сервер). Т.е. в моём случае, когда инициатором может выступать и сервер, лучше какую "конструкцию" сервера выбрать?
Может стоит посмотреть в сторону перекрытого ввод-вывода, реализованого через Event'ы ?
Здравствуйте, acDev, Вы писали:
D>Т.е. эта реализация обеспечивает протокол обмена типа: acceptEx -> получили запрос -> отправили ответ -> ждём запрос... D>У меня же протокол совсем не HTTP. У меня клиент может послать пакет серверу и при этом сервер не обязан на него отвечать. Да и сервер посылает клиенту команды, которые не требуют подтверждения.
D>Вот и не знаю как этот HTTP сервер передалать под мой протокол.
Ну и в чём трудность? Получили пакет, обработали. Если требуется ответ, отправляете его вызовом WsaSend, иначе вызываете WsaRecv
D>Да и не знаю как в этом сервере из любого другого потока в любой момент времени послать "моментально" данные клиенту. D>Да и можно ли использовать один и тот же сокет в разных потоках "одовременно"? D>Обязательно ли дожидаться окончания выполнения WSASend что бы вызвать WSARecv?
Нет.
И наоборот?
Тоже нет. Но вот с одновременным вызовом нескольких WsaSend или WsaRecv не столь однозначно, и дело даже не в потокобезопасности самих функций, с этим в асинхронном режиме всё в порядке. Трудности в логике обработки уведомлений о завершении. Например, если у Вас будет несколько активных запросов на чтение из одного сокета, то может статься, что уведомление о получении разных частей одного пакета Вы получите в разных потоках, и сборка такого пакета в единое целое может оказаться делом нетривиальным. И зачем оно? С несколькими WsaSend тоже есть проблема. Допустим, у Вас 10 потоков одновременно вызывают WsaSend. Достаточно высока вероятность, что несколько из них завершатся с ошибкой WSAEWOULDBLOCK, и для разруливания такой ситуации Вам всё равно придётся организовать ассоциированную с сокетом очередь отправки. На мой взгляд проще и надёжней сразу организовать такую очередь из структур WSABUF, и при получении уведомления о завершении WsaSend проверять её.
D>Ещё читал что, перекрытый ввод-вывод лучше подходит для обмена в режиме "запрос-ответ" (HTTP сервер). Т.е. в моём случае, когда инициатором может выступать и сервер, лучше какую "конструкцию" сервера выбрать? D>Может стоит посмотреть в сторону перекрытого ввод-вывода, реализованого через Event'ы ?
Я так не думаю.
"Нормальные герои всегда идут в обход!"
Re: Вопросы по асинх. TCP серверу с пулом потоков (IOCP)
Здравствуйте, acDev, Вы писали:
D>Т.е. эта реализация обеспечивает протокол обмена типа: acceptEx -> получили запрос -> отправили ответ -> ждём запрос... D>У меня же протокол совсем не HTTP. У меня клиент может послать пакет серверу и при этом сервер не обязан на него отвечать. Да и сервер посылает клиенту команды, которые не требуют подтверждения.
Ну это принципиально ничего не меняет. Если сервер не должен отвечать, он может просто закрыть соединение и забыть. С другой стороны, в таком случае непонятен смысл самого этого протокола. Чтобы так работать, или данные должны быть несущественны вообще, или достаточно часто повторяться, чтобы одиночные проблемы не приводили к существенной потере.
D>Вот и не знаю как этот HTTP сервер передалать под мой протокол.
В чём ещё разница в протоколах? Может ли, например, сервер присылать асинхронные оповещения? Насколько я понял по описанию — да, но тогда прошу изложить подробнее.
D>Да и не знаю как в этом сервере из любого другого потока в любой момент времени послать "моментально" данные клиенту. D>Да и можно ли использовать один и тот же сокет в разных потоках "одовременно"?
Лучше не надо. Или использовать блокировки мьютексами, критическими секциями, etc. для доставки, или делать то же самое для привязанного к сокету буфера, а собственно отправку по возможности — возложить на одну нить (уже не столь важно, какую).
D>Ещё читал что, перекрытый ввод-вывод лучше подходит для обмена в режиме "запрос-ответ" (HTTP сервер). Т.е. в моём случае, когда инициатором может выступать и сервер, лучше какую "конструкцию" сервера выбрать?
Насколько я понимаю, принципиальной разницы нет. Более того, различия протоколов (HTTP или что-то ещё) важны только до той степени, до которой они обеспечивают отделение разных посылок, идущих по одному TCP соединению. Приёмная сторона или собирает посылку целиком и тогда её передаёт на обработку, или определяет в её начале достаточно данных, чтобы определить метод поиска конца посылки и нужный обработчик (в случае HTTP для этого надо дочитать заголовок) и передаёт управление соответствующему обработчику. Передающая сторона или принимает посылку целиком, или получает блокиорвку на время завершения передачи. И в том и в другом случае i/o completion просто оповещает, что есть новые данные в сокете для приёма или освободилось место для передачи.
D>Может стоит посмотреть в сторону перекрытого ввод-вывода, реализованого через Event'ы ?
А в чём принципиальная разница? (не пишу под Windows)
The God is real, unless declared integer.
Re[2]: Вопросы по асинх. TCP серверу с пулом потоков (IOCP)
Здравствуйте, Jolly Roger, Вы писали:
JR>Ну и в чём трудность? Получили пакет, обработали. Если требуется ответ, отправляете его вызовом WsaSend, иначе вызываете WsaRecv
Т.е. могу сразу после вызова WSASend вызывать WSARecv , не дожидаяь при этом уведомления о завершении WSASend?
JR>Тоже нет. Но вот с одновременным вызовом нескольких WsaSend или WsaRecv не столь однозначно, и дело даже не в потокобезопасности самих функций, с этим в асинхронном режиме всё в порядке. Трудности в логике обработки уведомлений о завершении. Например, если у Вас будет несколько активных запросов на чтение из одного сокета, то может статься, что уведомление о получении разных частей одного пакета Вы получите в разных потоках, и сборка такого пакета в единое целое может оказаться делом нетривиальным. И зачем оно? С несколькими WsaSend тоже есть проблема. Допустим, у Вас 10 потоков одновременно вызывают WsaSend. Достаточно высока вероятность, что несколько из них завершатся с ошибкой WSAEWOULDBLOCK, и для разруливания такой ситуации Вам всё равно придётся организовать ассоциированную с сокетом очередь отправки. На мой взгляд проще и надёжней сразу организовать такую очередь из структур WSABUF, и при получении уведомления о завершении WsaSend проверять её.
Понятно. А если я текущий HTTP сервер переделаю так:
1) В потоке WorkThread буду читать данные через WSARecv и если требуется "срочный" ответ клиенту, то тут же вызываю WSASend (сейчаз в блокируемом сервере так и зделано).
2) Так же имеются "срочные" данные от самого сервера, которые будут тоже отправляться вызовом WSASend (это в отдельном потоке или потоках).
Как раз в этой схеме и возможна ситуация с перекрытым вызовом WSASend. Значит, как вы предлагаете, надо организовать очередь для WSASend.
Т.е. средует для каждого клиента выделить отдельный буфер для WSASend. А как правильно тогда обслуживать такой буфер, стремясь как можно быстре его "очистить"?
Здравствуйте, netch80, Вы писали:
D>>Т.е. эта реализация обеспечивает протокол обмена типа: acceptEx -> получили запрос -> отправили ответ -> ждём запрос... D>>У меня же протокол совсем не HTTP. У меня клиент может послать пакет серверу и при этом сервер не обязан на него отвечать. Да и сервер посылает клиенту команды, которые не требуют подтверждения.
N>Ну это принципиально ничего не меняет. Если сервер не должен отвечать, он может просто закрыть соединение и забыть. С другой стороны, в таком случае непонятен смысл самого этого протокола. Чтобы так работать, или данные должны быть несущественны вообще, или достаточно часто повторяться, чтобы одиночные проблемы не приводили к существенной потере.
Согласен частично. Просто тут коннект с клиентом постоянен на протяжении всей работы клиента. И когда я делал клиента на блокируемых сокетах мне совсем не хотелось делать ожидание ответов от сервера о приёме данных (что бы не тормозить работу).
Поступление важных данных проверятся сервером через спец. механизм. Поэтому если сервер поймёт что ему что то не пришло, то следует дисконнект.
D>>Вот и не знаю как этот HTTP сервер передалать под мой протокол.
N>В чём ещё разница в протоколах? Может ли, например, сервер присылать асинхронные оповещения? Насколько я понял по описанию — да, но тогда прошу изложить подробнее.
Если под асинхронными сообщениями понимаются данные, независящие от "запросов" клиента, то тогда может.
D>>Да и не знаю как в этом сервере из любого другого потока в любой момент времени послать "моментально" данные клиенту. D>>Да и можно ли использовать один и тот же сокет в разных потоках "одовременно"?
N>Лучше не надо. Или использовать блокировки мьютексами, критическими секциями, etc. для доставки, или делать то же самое для привязанного к сокету буфера, а собственно отправку по возможности — возложить на одну нить (уже не столь важно, какую).
Выше эту идею обмозговал чуточку ...
D>>Может стоит посмотреть в сторону перекрытого ввод-вывода, реализованого через Event'ы ?
N>А в чём принципиальная разница? (не пишу под Windows)
Да вот тоже думаю что нет особой разницы.
Re[3]: Вопросы по асинх. TCP серверу с пулом потоков (IOCP)
Здравствуйте, acDev, Вы писали:
D>Т.е. могу сразу после вызова WSASend вызывать WSARecv , не дожидаяь при этом уведомления о завершении WSASend?
Да.
D>Понятно. А если я текущий HTTP сервер переделаю так: D>1) В потоке WorkThread буду читать данные через WSARecv и если требуется "срочный" ответ клиенту, то тут же вызываю WSASend (сейчаз в блокируемом сервере так и зделано). D>2) Так же имеются "срочные" данные от самого сервера, которые будут тоже отправляться вызовом WSASend (это в отдельном потоке или потоках).
D>Как раз в этой схеме и возможна ситуация с перекрытым вызовом WSASend. Значит, как вы предлагаете, надо организовать очередь для WSASend. D>Т.е. средует для каждого клиента выделить отдельный буфер для WSASend. А как правильно тогда обслуживать такой буфер, стремясь как можно быстре его "очистить"?
Например, при попытке отправки смотрите, есть-ли незавершённые для данного сокета вызовы WsaSend. Если нет, то просто увеличиваете счётчик отправок и вызываете WsaSend, и при получении уведомления о завершении уменьшаете счётчик. Если есть, то добавляете данные в буфер. При получении уведомления о завершении WsaSend смотрите, есть-ли что-то в буфере, и если есть, то отправляете все данные, благо WsaSend принимает на входе список буферов. Закрыв всё это отдельной для каждого сокета крит. секцией, получите достаточно эффективный, простой и надёжный механизм.
"Нормальные герои всегда идут в обход!"
Re[4]: Вопросы по асинх. TCP серверу с пулом потоков (IOCP)
Здравствуйте, Jolly Roger, Вы писали:
D>>Т.е. могу сразу после вызова WSASend вызывать WSARecv , не дожидаяь при этом уведомления о завершении WSASend?
JR>Да.
Сейчаз же в HTTP сервере Overlapped структура одна на 1 сокет. Но сервак работает нормально, т.к. WSARecv вызывается после уведомления о выполненой WSASend.
В MSDN написано что при "одновременном" запуске WSARecv/WSASend я должен использовать разные Overlapped структуры.
Ну WSARecv я решил что будет в одном месте юзаться и поэтому использую для него ту структуру, что уже используется в контексте конкретного клиента. А вот под WSASend видимо придётся сделать отдельную структурку Overlapped.
Я правильно понял?
JR>Например, при попытке отправки смотрите, есть-ли незавершённые для данного сокета вызовы WsaSend.
Смотреть на счётчик вызовов WSASend для данного сокета?
JR>Если нет, то просто увеличиваете счётчик отправок и вызываете WsaSend, и при получении уведомления о завершении уменьшаете счётчик. Если есть, то добавляете данные в буфер. При получении уведомления о завершении WsaSend смотрите, есть-ли что-то в буфере, и если есть, то отправляете все данные, благо WsaSend принимает на входе список буферов. Закрыв всё это отдельной для каждого сокета крит. секцией, получите достаточно эффективный, простой и надёжный механизм.
Значит так и буду пытаться сделать. Спасибо.
----------------------
Тут ещё вопросики созрели при использовании WSAxxxx в режиме IOCP (MSDN мало что дал):
Что означает если WSARecv возвращает WSAEWOULDBLOCK ?
Что означает если WSASend возвращает WSAEWOULDBLOCK ?
Может ли WSASend возвратить в lpNumberOfBytesTransferred (параметр ф-ии GetQueuedCompletionStatus) число меньшее чем суммарный размер буферов переданных через параметр LPWSABUF lpBuffers ?
Ну 0 возвратить может (это означает "потерю" клиента).
Re[3]: Вопросы по асинх. TCP серверу с пулом потоков (IOCP)
Здравствуйте, acDev, Вы писали:
D>Понятно. А если я текущий HTTP сервер переделаю так: D>1) В потоке WorkThread буду читать данные через WSARecv и если требуется "срочный" ответ клиенту, то тут же вызываю WSASend (сейчаз в блокируемом сервере так и зделано). D>2) Так же имеются "срочные" данные от самого сервера, которые будут тоже отправляться вызовом WSASend (это в отдельном потоке или потоках).
Всё-таки непонятна организация протокола. Он синхронный или асинхронный? Запросы и ответы тегированы или нет?
D>Как раз в этой схеме и возможна ситуация с перекрытым вызовом WSASend. Значит, как вы предлагаете, надо организовать очередь для WSASend.
Или таки для посылок? Создайте при сокете очередь посылок, а на передающую нить нагрузите задачу передачи всего, что накопилось в этой очереди.
D>Т.е. средует для каждого клиента выделить отдельный буфер для WSASend. А как правильно тогда обслуживать такой буфер, стремясь как можно быстре его "очистить"?
Очень просто Есть возможность добавить данные — добавлять. Нет — ждать. Надоело ждать — рвать соединение.
N>>В чём ещё разница в протоколах? Может ли, например, сервер присылать асинхронные оповещения? Насколько я понял по описанию — да, но тогда прошу изложить подробнее. D>Если под асинхронными сообщениями понимаются данные, независящие от "запросов" клиента, то тогда может.
Значит, как я сказал выше.
The God is real, unless declared integer.
Re[5]: Вопросы по асинх. TCP серверу с пулом потоков (IOCP)
Здравствуйте, acDev, Вы писали:
D>Сейчаз же в HTTP сервере Overlapped структура одна на 1 сокет. Но сервак работает нормально, т.к. WSARecv вызывается после уведомления о выполненой WSASend. D>В MSDN написано что при "одновременном" запуске WSARecv/WSASend я должен использовать разные Overlapped структуры. D>Ну WSARecv я решил что будет в одном месте юзаться и поэтому использую для него ту структуру, что уже используется в контексте конкретного клиента. А вот под WSASend видимо придётся сделать отдельную структурку Overlapped. D>Я правильно понял?
Overlapped, точнее её адрес, — это "этикетка" асинхронного запроса, с её помощью и стек драйверов, и Ваш код отличают один такой запрос от другого. Естественно, её нельзя использовать повторно до завершения предыдущего запроса, в который Вы её передали, иначе Вы не сможете понять, на какой из запросов Вы получили уведомление о завершении.
JR>>Например, при попытке отправки смотрите, есть-ли незавершённые для данного сокета вызовы WsaSend.
D>Смотреть на счётчик вызовов WSASend для данного сокета?
Да, на индивидуальный для каждого гнезда счётчик, который Вы сами должны организовать и поддерживать в актуальном состоянии.
D>---------------------- D>Тут ещё вопросики созрели при использовании WSAxxxx в режиме IOCP (MSDN мало что дал): D>Что означает если WSARecv возвращает WSAEWOULDBLOCK ? D>Что означает если WSASend возвращает WSAEWOULDBLOCK ?
Она всегда означает одно — в данный момент система не может выполнить запрошенную операцию с этим экземпляром сокета, необходимо попробовать повторить её позже. На WSARecv получить её маловероятно, разве что в случае грубой ошибки в логике. А вот для WSASend это более вероятно, возникает при попытке передавать данные быстрее, чем стек реально может их отправить. Её легко сымитировать, вызвав два раза подряд WSASend с большим блоком данных, 1 МБ, например, при дефолтном размере буфера передачи.
D>Может ли WSASend возвратить в lpNumberOfBytesTransferred (параметр ф-ии GetQueuedCompletionStatus) число меньшее чем суммарный размер буферов переданных через параметр LPWSABUF lpBuffers ? D>Ну 0 возвратить может (это означает "потерю" клиента).
Теоретически это возможно и должно означать, что на часть данных от корреспондента получена квитанция, после чего связь была потеряна. Однако на практике я такого не встречал.
"Нормальные герои всегда идут в обход!"
Re[6]: Вопросы по асинх. TCP серверу с пулом потоков (IOCP)
Здравствуйте, Jolly Roger, Вы писали:
D>>---------------------- D>>Тут ещё вопросики созрели при использовании WSAxxxx в режиме IOCP (MSDN мало что дал): D>>Что означает если WSARecv возвращает WSAEWOULDBLOCK ? D>>Что означает если WSASend возвращает WSAEWOULDBLOCK ?
JR>Она всегда означает одно — в данный момент система не может выполнить запрошенную операцию с этим экземпляром сокета, необходимо попробовать повторить её позже. На WSARecv получить её маловероятно, разве что в случае грубой ошибки в логике.
Ну почему же. Есть сообщение о возможности читать, читаем — раз, два, три... на очередной попытке чтения нам говорят, что данных больше нет, вот тогда прекращаем (и запрашиваем следующую нотификацию). Не заводить же сразу буфер на максимальный размер одной посылки? Это будет просто неэкономным.
Так что [WSA]EWOULDBLOCK из чтения — абсолютно нормально.
D>>Может ли WSASend возвратить в lpNumberOfBytesTransferred (параметр ф-ии GetQueuedCompletionStatus) число меньшее чем суммарный размер буферов переданных через параметр LPWSABUF lpBuffers ? D>>Ну 0 возвратить может (это означает "потерю" клиента).
JR>Теоретически это возможно и должно означать, что на часть данных от корреспондента получена квитанция, после чего связь была потеряна. Однако на практике я такого не встречал.
Это, кстати, крайне странный теоретический вариант — потому что нелогичный код.
The God is real, unless declared integer.
Re[6]: Вопросы по асинх. TCP серверу с пулом потоков (IOCP)
Здравствуйте, netch80, Вы писали:
N>Всё-таки непонятна организация протокола. Он синхронный или асинхронный? Запросы и ответы тегированы или нет?
Он "асинхронный". Т.е. тут нет таких понятий как запрос и ответ. У меня в протоколе просто данные передаются. Контроль доставки критичных данных есть.
D>>Как раз в этой схеме и возможна ситуация с перекрытым вызовом WSASend. Значит, как вы предлагаете, надо организовать очередь для WSASend.
N>Или таки для посылок? Создайте при сокете очередь посылок, а на передающую нить нагрузите задачу передачи всего, что накопилось в этой очереди.
Так и буду делать.
D>>Т.е. средует для каждого клиента выделить отдельный буфер для WSASend. А как правильно тогда обслуживать такой буфер, стремясь как можно быстре его "очистить"?
N>Очень просто Есть возможность добавить данные — добавлять. Нет — ждать. Надоело ждать — рвать соединение.
Ок.
-----------------
Здравствуйте, Jolly Roger, Вы писали:
D>>Что означает если WSARecv возвращает WSAEWOULDBLOCK ? D>>Что означает если WSASend возвращает WSAEWOULDBLOCK ?
JR>Она всегда означает одно — в данный момент система не может выполнить запрошенную операцию с этим экземпляром сокета, необходимо попробовать повторить её позже. На WSARecv получить её маловероятно, разве что в случае грубой ошибки в логике. А вот для WSASend это более вероятно, возникает при попытке передавать данные быстрее, чем стек реально может их отправить. Её легко сымитировать, вызвав два раза подряд WSASend с большим блоком данных, 1 МБ, например, при дефолтном размере буфера передачи.
В чём различие 2-х разных ситуаций:
1) Получаем WSAEWOULDBLOCK сразу после вызова WSASend.
2) Получаем WSAEWOULDBLOCK (через GetLastError) после вызова GetQueuedCompletionStatus (FALSE) (в контексте WSASend) ?
Re[7]: Вопросы по асинх. TCP серверу с пулом потоков (IOCP)
Здравствуйте, netch80, Вы писали:
JR>>Она всегда означает одно — в данный момент система не может выполнить запрошенную операцию с этим экземпляром сокета, необходимо попробовать повторить её позже. На WSARecv получить её маловероятно, разве что в случае грубой ошибки в логике.
N>Ну почему же. Есть сообщение о возможности читать, читаем — раз, два, три... на очередной попытке чтения нам говорят, что данных больше нет, вот тогда прекращаем (и запрашиваем следующую нотификацию). Не заводить же сразу буфер на максимальный размер одной посылки? Это будет просто неэкономным. N>Так что [WSA]EWOULDBLOCK из чтения — абсолютно нормально.
Да, в случае синхронного неблокирующего режима. А я рассматривал overlapped режим, автора топика ведь именно он интересует. Но Вы правы, следовало об этом явно сказать.
"Нормальные герои всегда идут в обход!"
Re[7]: Вопросы по асинх. TCP серверу с пулом потоков (IOCP)
Здравствуйте, acDev, Вы писали:
D>В чём различие 2-х разных ситуаций: D>1) Получаем WSAEWOULDBLOCK сразу после вызова WSASend. D>2) Получаем WSAEWOULDBLOCK (через GetLastError) после вызова GetQueuedCompletionStatus (FALSE) (в контексте WSASend) ?
А второй вариант в природе бывает? Я не встречал
"Нормальные герои всегда идут в обход!"
Re[8]: Вопросы по асинх. TCP серверу с пулом потоков (IOCP)
Здравствуйте, Jolly Roger, Вы писали:
JR>Здравствуйте, acDev, Вы писали:
D>>В чём различие 2-х разных ситуаций: D>>1) Получаем WSAEWOULDBLOCK сразу после вызова WSASend. D>>2) Получаем WSAEWOULDBLOCK (через GetLastError) после вызова GetQueuedCompletionStatus (FALSE) (в контексте WSASend) ?
JR>А второй вариант в природе бывает? Я не встречал
Да в HTTP сервере, который я взял за основу, есть такая проверка.
1) Т.е. когда GetQueuedCompletionStatus возвращает FALSE и GetLastError != WSAEWOULDBLOCK , то следует дисконнект.
2) Ну и если GetQueuedCompletionStatus возвращает TRUE , а lpNumberOfBytesTransferred == 0 , то следует дисконнект.
Второе мне понятно, а вот про 1-ое нигде и не читал.
Re[9]: Вопросы по асинх. TCP серверу с пулом потоков (IOCP)
Здравствуйте, Jolly Roger, Вы писали:
JR>>>Она всегда означает одно — в данный момент система не может выполнить запрошенную операцию с этим экземпляром сокета, необходимо попробовать повторить её позже. На WSARecv получить её маловероятно, разве что в случае грубой ошибки в логике.
N>>Ну почему же. Есть сообщение о возможности читать, читаем — раз, два, три... на очередной попытке чтения нам говорят, что данных больше нет, вот тогда прекращаем (и запрашиваем следующую нотификацию). Не заводить же сразу буфер на максимальный размер одной посылки? Это будет просто неэкономным. N>>Так что [WSA]EWOULDBLOCK из чтения — абсолютно нормально.
JR>Да, в случае синхронного неблокирующего режима.
Не только. В сокет пришло 5 килобайт, а вычитывается порциями по 2 килобайта. Сколько чтений на одну нотификацию надо сделать? Безусловно больше одного
JR> А я рассматривал overlapped режим, автора топика ведь именно он интересует. Но Вы правы, следовало об этом явно сказать.
Угу, ещё и потому, что для асинхронного та же проблема. Или проверять, сколько ещё есть, в явных числах через что-то вроде FIONREAD, или долбиться до явного отказа.
The God is real, unless declared integer.
Re[9]: Вопросы по асинх. TCP серверу с пулом потоков (IOCP)
Здравствуйте, acDev, Вы писали:
D>Здравствуйте, Jolly Roger, Вы писали:
JR>>Здравствуйте, acDev, Вы писали:
D>>>В чём различие 2-х разных ситуаций: D>>>1) Получаем WSAEWOULDBLOCK сразу после вызова WSASend. D>>>2) Получаем WSAEWOULDBLOCK (через GetLastError) после вызова GetQueuedCompletionStatus (FALSE) (в контексте WSASend) ?
JR>>А второй вариант в природе бывает? Я не встречал
D>Да в HTTP сервере, который я взял за основу, есть такая проверка. D>1) Т.е. когда GetQueuedCompletionStatus возвращает FALSE и GetLastError != WSAEWOULDBLOCK , то следует дисконнект.
Э, так тут же _не_ равно WSAEWOULDBLOCK. То есть смысл — "иная ошибка, нежели временное отсутствие данных". Тогда он рвёт по ошибке сокета.
The God is real, unless declared integer.
Re[7]: Вопросы по асинх. TCP серверу с пулом потоков (IOCP)
Здравствуйте, acDev, Вы писали:
N>>Всё-таки непонятна организация протокола. Он синхронный или асинхронный? Запросы и ответы тегированы или нет? D>Он "асинхронный". Т.е. тут нет таких понятий как запрос и ответ. У меня в протоколе просто данные передаются. Контроль доставки критичных данных есть.
Ясно. Тогда надо заказывать и передачу, и приём одновременно по необходимости, но не более одного заказа на один тип деятельности одновременно на одно соединение. Это всё уже описано в предыдущих письмах.
The God is real, unless declared integer.
Re[9]: Вопросы по асинх. TCP серверу с пулом потоков (IOCP)
Здравствуйте, netch80, Вы писали:
JR>>Да, в случае синхронного неблокирующего режима.
N>Не только. В сокет пришло 5 килобайт, а вычитывается порциями по 2 килобайта. Сколько чтений на одну нотификацию надо сделать? Безусловно больше одного
JR>> А я рассматривал overlapped режим, автора топика ведь именно он интересует. Но Вы правы, следовало об этом явно сказать.
N>Угу, ещё и потому, что для асинхронного та же проблема. Или проверять, сколько ещё есть, в явных числах через что-то вроде FIONREAD, или долбиться до явного отказа.
Не понял Читая по 2К, мы в случае синхронного неблокирующего режима получим EWOULDBLOCK на 4-й вызов.
В случае синхронного блокирующего 4-й вызов не завершится, пока либо не придут данные, либо не истечёт таймаут, либо не будет закрвто соединение. Ни в одном из этих случаев EWOULDBLOCK не будет возвращён.
В случае overlapped режима мы получим IO_PENDING. Далее, при приходе данных либо разрыве соединения к нам придёт уведомление об успешном завершении операции, либо код ошибки, соответствующий причине потери связи. EWOULDBLOCK к таким причинам не относится, и, соответственно, никогда в этом месте не возвращается.
В чём я не прав? Опишите сценарий, при котором WsaRecv вернёт ошибку в асинхронном (overlapped) режиме.
"Нормальные герои всегда идут в обход!"
Re[2]: Вопросы по асинх. TCP серверу с пулом потоков (IOCP)
Здравствуйте, Jolly Roger, Вы писали:
JR>Тоже нет. Но вот с одновременным вызовом нескольких WsaSend или WsaRecv не столь однозначно, и дело даже не в потокобезопасности самих функций, с этим в асинхронном режиме всё в порядке. Трудности в логике обработки уведомлений о завершении. Например, если у Вас будет несколько активных запросов на чтение из одного сокета, то может статься, что уведомление о получении разных частей одного пакета Вы получите в разных потоках, и сборка такого пакета в единое целое может оказаться делом нетривиальным. И зачем оно?
Затем чтобы исключить копирования из внутренних буферов стэка при Recv, ведь если операции чтения нет в очереди — этого не избежать. Это одна из ключевых фич IOCP.
Для send все не так очевидно, своя очередь — получается дублирует механизм предаставляемый стеком, что не есть правильно ИМХО.
Re[3]: Вопросы по асинх. TCP серверу с пулом потоков (IOCP)
Здравствуйте, vf, Вы писали:
JR>>Тоже нет. Но вот с одновременным вызовом нескольких WsaSend или WsaRecv не столь однозначно, и дело даже не в потокобезопасности самих функций, с этим в асинхронном режиме всё в порядке. Трудности в логике обработки уведомлений о завершении. Например, если у Вас будет несколько активных запросов на чтение из одного сокета, то может статься, что уведомление о получении разных частей одного пакета Вы получите в разных потоках, и сборка такого пакета в единое целое может оказаться делом нетривиальным. И зачем оно?
vf>Затем чтобы исключить копирования из внутренних буферов стэка при Recv, ведь если операции чтения нет в очереди — этого не избежать. Это одна из ключевых фич IOCP.
vf>Для send все не так очевидно, своя очередь — получается дублирует механизм предаставляемый стеком, что не есть правильно ИМХО.
Вы не правы. На сервере есть такие функции, которые хотят клиенту кинуть срочные данные. И если при этом буфер исходящих сообщений полон, то эти функции совсем "не хотят" ожидать пока там данные уйдут в сеть (пока от очередного вызова WSASend сработает GetQueuedCompletionStatus).
Эти функции просто в крит. секции должны копировать данные в спец. буфер отправки и работать дальше. А уж отдельный поток пусть сам дожидаться уведомления о выполнении WSASend и вызывает следующий WSASend.