Простой вопросик для тех кто в теме.
Длина пришедших данных больше размера буфера. Крутим цикл динамически увеличивая размер буфера дописывая туда данные.
Мой колбэк на порту завершения будет вызван:
а. как только заполнен весь буфер и в каждый последующий цикл при дочитывании данных;
б. как только считаются все данные из очереди.
Надеюсь, что понятно задал вопрос. Спасибо.
PS. По форуму искал и в гугле был. Но, не исключено, что просто не нашел. На вашем форуме в первые, сильно не пинать
Твой callback будет вызван как только будут готовы данные для него. Ориентироваться при обработке принятых данных нужно только на lpNumberOfBytesTransfered.
Здравствуйте, Aspire, Вы писали:
A>Мой колбэк на порту завершения будет вызван:
... на каждый успешный вызов WSARecv. Вызов WSARecv считается успешным, если он вернул 0 или ошибку WSA_IO_PENDING.
Это единственное, на что можешь рассчитывать. Все остальные зависимости (от размера буфера, количества поступивших данных и т.п.) будут работать с разной степенью частоты — от "никогда" до "иногда".
Здравствуйте, Michael Chelnokov, Вы писали:
MC>... на каждый успешный вызов WSARecv. Вызов WSARecv считается успешным, если он вернул 0 или ошибку WSA_IO_PENDING.
MC>Это единственное, на что можешь рассчитывать. Все остальные зависимости (от размера буфера, количества поступивших данных и т.п.) будут работать с разной степенью частоты — от "никогда" до "иногда".
Это да, но на каждый WSARecv callback может быть вызван несколько раз.
Колбэк на порту завершения будет вызван:
MC>... на каждый успешный вызов WSARecv. Вызов WSARecv считается успешным, если он вернул 0 или ошибку WSA_IO_PENDING.
MC>Это единственное, на что можешь рассчитывать. Все остальные зависимости (от размера буфера, количества поступивших данных и т.п.) будут работать с разной степенью частоты — от "никогда" до "иногда".
Спасибо за ответ! Стало еще интереснее. Буду эксперементировать
Здравствуйте, Michael Chelnokov, Вы писали:
MC>Нет. Один и только один раз.
Ну да, спутал с GetQueuedCompletionStatus.
Re[2]: completion port, WSARecv, buflen
От:
Аноним
Дата:
18.02.09 18:38
Оценка:
Здравствуйте, Michael Chelnokov, Вы писали:
MC>Здравствуйте, Aspire, Вы писали:
MC>Колбэк на порту завершения будет вызван:
MC>... на каждый успешный вызов WSARecv. Вызов WSARecv считается успешным, если он вернул 0 или ошибку WSA_IO_PENDING.
MC>Это единственное, на что можешь рассчитывать. Все остальные зависимости (от размера буфера, количества поступивших данных и т.п.) будут работать с разной степенью частоты — от "никогда" до "иногда".
В связи с этим, следующий вопрос. Как мне на порту завершения получить уведомление о том, что получены все данные?
В случае с WSASend, можно, конечно, передать в конце структуры WSAOVERLAPPED размер передаваемых данных, а в обработчике складывать отправленные байты отдельно для каждого сокета, но мне кажется этот вариант не очень удачным. Опять же, как поступать в этом случае с WSARecv, где мы не знаем конечный размер данных?
Может, забить на колбэк порта и стартовать обработчик по эвэнту?
Здравствуйте, Аноним, Вы писали:
MC>>Колбэк на порту завершения будет вызван: MC>>... на каждый успешный вызов WSARecv. Вызов WSARecv считается успешным, если он вернул 0 или ошибку WSA_IO_PENDING.
А>В связи с этим, следующий вопрос. Как мне на порту завершения получить уведомление о том, что получены все данные?
Никак. Ты заказал операцию ввода/вывода, по ее окончании тебе пришло уведомление. В уведомлении сказано, сколько байт было передано или принято. В пределах [0 ... заказанное количество].
А>В случае с WSASend, можно, конечно, передать в конце структуры WSAOVERLAPPED размер передаваемых данных, а в обработчике складывать отправленные байты отдельно для каждого сокета, но мне кажется этот вариант не очень удачным. Опять же, как поступать в этом случае с WSARecv, где мы не знаем конечный размер данных?
Не понял проблемы.
А>Может, забить на колбэк порта и стартовать обработчик по эвэнту?
Не знаю. Не совсем понятно, что ты понимаешь под "колбэк порта", и чем "обработчик по эвэнту" лучше него.
Здравствуйте, Michael Chelnokov, Вы писали: MC>Никак. Ты заказал операцию ввода/вывода, по ее окончании тебе пришло уведомление. В уведомлении сказано, сколько байт было передано или принято. В пределах [0 ... заказанное количество].
В таком случае, обработка события на порту завершения теряет всякий смысл, поскольку, я не могу произвести никаких действий пока не придут все данные. Память не освободить, сообщение об успехе в гуи не послать и тд..
MC>Не понял проблемы.
Вытекает из предыдущей.
А>>Может, забить на колбэк порта и стартовать обработчик по эвэнту?
MC>Не знаю. Не совсем понятно, что ты понимаешь под "колбэк порта", и чем "обработчик по эвэнту" лучше него.
Ну, допустим у нас есть поток, который ждет события "все данные получены/отправлены", которое я взвожу, когда WSARecv/WSASend после нуля возвратят WSA_IO_PENDING. С этим событием поток стартует и подчищает ресурсы, посылает сообщения и пр. Преимущество в том, что в этом случае, не производя никаких вычислений по кол-ву отправленных/принятых байт мы узнаем о завершении ввода всего кол-ва данных.
А вообще, хотелось бы линк на пример использования порта завершения при операциях чтения/записи на сокетах, чтобы понять как это было бы по правильному при большом потоке данных. Все классические примеры в гугле рассмативают IOCP в применении к accept.
В принципе-то, рабочий пример я накатал, но не могу понять как обрабатывать события, если все данные не получить/отправить за один вызов.
Здравствуйте, Aspire, Вы писали:
A>В таком случае, обработка события на порту завершения теряет всякий смысл, поскольку, я не могу произвести никаких действий пока не придут все данные. Память не освободить, сообщение об успехе в гуи не послать и тд..
Что у тебя за надуманные проблемы? Ты же работаешь не со сферическим конем, а с конкретным, тобой определенным протоколом. В протоколе, например, первыми байтами идет размер пакета. Принимая пакет по частям ты складываешь его в буфер (если пакет большой и не пришел за один раз). Принял пакет полностью — обрабатываешь.
А>>>Может, забить на колбэк порта и стартовать обработчик по эвэнту?
Учитываем, что никому не понятно что ты _имеешь ввиду_ и пишем понятней.
A>Ну, допустим у нас есть поток, который ждет события "все данные получены/отправлены", которое я взвожу, когда WSARecv/WSASend после нуля возвратят WSA_IO_PENDING. С этим событием поток стартует и подчищает ресурсы, посылает сообщения и пр. Преимущество в том, что в этом случае, не производя никаких вычислений по кол-ву отправленных/принятых байт мы узнаем о завершении ввода всего кол-ва данных.
[утирает пот] Круто. Т.е. завершение операции ты не дожидаешься?
A>А вообще, хотелось бы линк на пример использования порта завершения при операциях чтения/записи на сокетах, чтобы понять как это было бы по правильному при большом потоке данных. Все классические примеры в гугле рассмативают IOCP в применении к accept.
Да ладно. Есть куча нормальных примеров, что здесь, что, например, на codeproject.
Здравствуйте, Gomes, Вы писали:
G>Что у тебя за надуманные проблемы? Ты же работаешь не со сферическим конем, а с конкретным, тобой определенным протоколом. В протоколе, например, первыми байтами идет размер пакета. Принимая пакет по частям ты складываешь его в буфер (если пакет большой и не пришел за один раз). Принял пакет полностью — обрабатываешь.
Если я правильно понял, Вы имеете ввиду, что в прикладном протоколе нужно-таки передавать размер отосланных данных, принимать их на клиенте и передавать обработчику порта завершения (GetQueuedCompletionStatus), который, при большом объеме данных будет частями дописывать буфер сравнивая сумму пришедших с общим размером..
Я, действительно, пытался поработать со сферическим конем в вакууме, получая данные не зная конечного размера. Жаль не получилось.
G>[утирает пот] Круто. Т.е. завершение операции ты не дожидаешься?
Упс...
G>Да ладно. Есть куча нормальных примеров, что здесь, что, например, на codeproject.
Продолжу задавать вопросы в данном топе, дабы не плодить темы. Тем более, что вопрос, вроде, по теме.
С сервера, большому количеству клиентов, отправляется большой кусок данных с помощью WSASend и completion port.
Для того, чтобы своевременно подчистить ресурсы, мне необходимо отседить на колл-бэке порта завершения (GetQueuedCompletionStatus), что отправлены все данные.
Сначала, я предполагал поступить следующим образом. Я поместил структуру WSABUF в конец структуры WSAOVERLAPPED, указатель на которую передается на ф-ции GetQueuedCompletionStatus, с каждым следующим вызовом WSASend, я увеличивал указатель на буфер (WSABUF.buf) на количество отправленных байт, которое возвращала мне WSASend и уменьшал размер буфера (WSABUF.len) на туже величину. На обработчике порта проверял значение WSABUF.len на NULL, что означало бы, что все данные отправлены. Вроде, все логично, НО, потом я вспомнил, что это перекрытый ввод/вывод, а структура WSABUF у меня одна на каждый вызов WSASend и, скорее всего, я ее перезапишу несколько раз до того, как закончится первая операция ввода/вывода и будет вызван мой обработчик.
pMem->wsb.len = szData;
pMem->wsb.buf = pBuf;
while( ! (WSASend(S_BUF[i], &pMem->wsb, 1, (LPDWORD)&BytesSent, 0, (LPWSAOVERLAPPED)pMem, 0))){ // Ловим результат на порту завершения
pMem->wsb.len -= BytesSent;
pMem->wsb.buf += BytesSent;
}
Получается, что для каждого вызова WSASend нужен свой буфер под структуру WSAOVERLAPPED, за которой я поместил структуру WSABUF, указатель на которую передается моему обрабочику GetQueuedCompletionStatus.
Прав ли я?
Как можно оптимизировать данную ситуацию?
Может, я все собираюсь делать через *опу и нужно делать совсем не так?
Если клиентов много, то выделять столько памяти — это слишком расточительно, и если этого не избежать, то придется выделять память под стуктуры из связного списка, а на обработчике сразу ее возвращать обратно.
Помогите разобраться в данной ситуевине. Запуталсо...
Здравствуйте, Aspire, Вы писали:
A>Получается, что для каждого вызова WSASend нужен свой буфер под структуру WSAOVERLAPPED,... A>Прав ли я?
Да.
A>Как можно оптимизировать данную ситуацию?
Зачем?
A>Если клиентов много, то выделять столько памяти — это слишком расточительно,
"Много" — это сколько? Считаем 10к одновременных. На 64-битной машине sizeof(OVERLAPPED) — 32 байта. И, скажем, 8 твоих. Плюс накладные расходы. Итого 400к-500к на все. Менее 0,1% от абсолютно минимального количества памяти на сервере, который может потянуть такую нагрузку. Не смеши, это не расточительство.
A>и если этого не избежать, то придется выделять память под стуктуры из связного списка, а на обработчике сразу ее возвращать обратно.
Да, только это не из-за "расточительства", а во избежание излишней фрагментации кучи. Очень актуально в сервисах, работающих много времени без перезапуска.
Здравствуйте, Michael Chelnokov, Вы писали:
MC>Здравствуйте, Aspire, Вы писали:
A>>Получается, что для каждого вызова WSASend нужен свой буфер под структуру WSAOVERLAPPED,... A>>Прав ли я?
MC>Да.
A>>Как можно оптимизировать данную ситуацию?
MC>Зачем?
A>>Если клиентов много, то выделять столько памяти — это слишком расточительно,
MC>"Много" — это сколько? Считаем 10к одновременных. На 64-битной машине sizeof(OVERLAPPED) — 32 байта. И, скажем, 8 твоих. Плюс накладные расходы. Итого 400к-500к на все. Менее 0,1% от абсолютно минимального количества памяти на сервере, который может потянуть такую нагрузку. Не смеши, это не расточительство.
A>>и если этого не избежать, то придется выделять память под стуктуры из связного списка, а на обработчике сразу ее возвращать обратно.
MC>Да, только это не из-за "расточительства", а во избежание излишней фрагментации кучи. Очень актуально в сервисах, работающих много времени без перезапуска.
Все гораздо хуже. Допустим, нам нужно каждому клиенту (из 10к) отправить 40 метров. У меня на 32 битной машине, WSARecv за одни раз принимает ~17кб (и то с третьего вызова 4.4-8.8-17.6). Предположу, что для WSASend ситуация будет такая же. Получается, для на одного клиента, мы вызовем WSASend около 2400 раз. Для каждого вызова выделим память под структуры OVERLAPPED и WSABUF, т.е., по 40 байт. Итого: (2400*40*10000)/(1024*1024) = 915.5 Мб!
Здравствуйте, Aspire, Вы писали:
A>Все гораздо хуже. Допустим, нам нужно каждому клиенту (из 10к) отправить 40 метров. У меня на 32 битной машине, WSARecv за одни раз принимает ~17кб (и то с третьего вызова 4.4-8.8-17.6). Предположу, что для WSASend ситуация будет такая же. Получается, для на одного клиента, мы вызовем WSASend около 2400 раз. Для каждого вызова выделим память под структуры OVERLAPPED и WSABUF, т.е., по 40 байт. Итого: (2400*40*10000)/(1024*1024) = 915.5 Мб!
Ты же WSASend будешь последовательно вызывать для того же клиента. Используй структуру OVERLAPPED с предыдущего раза. А если ты хочешь сразу пачку WSASend вызвать, не дожидаясь завершения предыдущей отсылки, то это плохая идея. Кто тебе сказал, что данные не перемешаются?
Здравствуйте, Michael Chelnokov, Вы писали:
MC>Здравствуйте, Aspire, Вы писали:
A>>Все гораздо хуже. Допустим, нам нужно каждому клиенту (из 10к) отправить 40 метров. У меня на 32 битной машине, WSARecv за одни раз принимает ~17кб (и то с третьего вызова 4.4-8.8-17.6). Предположу, что для WSASend ситуация будет такая же. Получается, для на одного клиента, мы вызовем WSASend около 2400 раз. Для каждого вызова выделим память под структуры OVERLAPPED и WSABUF, т.е., по 40 байт. Итого: (2400*40*10000)/(1024*1024) = 915.5 Мб!
MC>Ты же WSASend будешь последовательно вызывать для того же клиента. Используй структуру OVERLAPPED с предыдущего раза. А если ты хочешь сразу пачку WSASend вызвать, не дожидаясь завершения предыдущей отсылки, то это плохая идея. Кто тебе сказал, что данные не перемешаются?
Мне нельзя использовать стуктуру с предыдущего раза, т.к., за этой структурой я помещаю структуру WSABUF, в которой с каждым вызовом WSASend уменьшаю .len на кол-во отправленных байт, а указатель .buf увеличиваю на туже величину. В обработчике GetQueuedCompletionStatus, получая указатель на эту структуру, я проверяю .len на ноль, что означает, что все 40Мб (например) отправлены и предпринимаю в связи с этим определенные действия. Если я буду использовать предыдущую, то данные в ней будут перетираться с каждым вызовом WSASend и я не смогу получить адекватную информацию о завершении передачи всех данных на обработчике порта.
Здравствуйте, Michael Chelnokov, Вы писали:
MC>А если ты хочешь сразу пачку WSASend вызвать, не дожидаясь завершения предыдущей отсылки, то это плохая идея. Кто тебе сказал, что данные не перемешаются?
То есть, вы хотите сказать, что вызывать WSASend в цикле, как в #6, это неправильно и нужно сначала дождаться первой отправки (на обработчике порта завершения?) и только потом вызывать второй WSASend???
Или я вас неправильно понял?
Здравствуйте, Aspire, Вы писали:
A>То есть, вы хотите сказать, что вызывать WSASend в цикле, как в #6, это неправильно и нужно сначала дождаться первой отправки (на обработчике порта завершения?) и только потом вызывать второй WSASend???
Именно так.
Здравствуйте, Gomes, Вы писали:
G>Здравствуйте, Aspire, Вы писали:
A>>То есть, вы хотите сказать, что вызывать WSASend в цикле, как в #6, это неправильно и нужно сначала дождаться первой отправки (на обработчике порта завершения?) и только потом вызывать второй WSASend??? G>Именно так.
Да ну на?! А в чем тогда преимущество перекрытого ввода/вывода в этом случае? Тогда бы я просто юзал блокирующий send.
Подскажите правильный алгоритм, тогда.
Еще больше запуталсо. А проверить на примере, смогу только вечером...